InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Custom OWA Forms in Exchange 2007 – Refreshing OWA after editing a custom element

This is some sort of follow up to yesterdays post about custom OWA forms. If a user opens an OWA form for editing, OWA opens the edit form for the item in a new window. In most forms, a click on the “Save” button will also close this window and OWA will reload the preview window as well as the items list via a custom AJAX call. Unfortunately, Microsoft has not documented how to do this for custom forms, so the method described here is to be considered totally unsupported, and it may stop to work with any future service pack or roll-up.

Two javascript functions have to be called to execute a refresh of both the preview pane and the items list:

   1: window.opener.ref();      // refresh the list view
   2: window.opener.udRP(1);    // refresh the reading pane
   3: window.close();           // close the edit window

If you followed my steps from the last post, you can use a standard button (or link button) to create your own save button. In that case, use the following code to emit the required script:

   1: protected void SaveButton_Click(object sender, EventArgs e)
   2: {
   3:     if (!Page.IsValid)
   4:     {
   5:         return;
   6:     }
   7:  
   8:     // Do what is necessary to save the changes made by the user
   9:         
  10:     Response.ClearContent();
  11:     Response.Write("<script language='javascript'>window.opener.ref(); window.opener.udRP(1); window.close();</script>");
  12:     Response.End();
  13: }

Posted by Henning Krause on Tuesday, March 24, 2009 10:17 PM, last modified on Monday, November 29, 2010 6:49 PM
Permalink | Post RSSRSS comment feed

Custom OWA Forms in Exchange 2007 – Reenabling standard postback functionality

With Service Pack 1, Microsoft introduced some features with Outlook Web Access that allows a developer to create custom forms. These custom forms can be used to display and edit items with custom message classes, much like Outlook does. Details of these features can be found on MSDN here and here and fellow MVP Glen Scales has an example here. Basically, all one needs to do is creating some formulas (in the form of .aspx files) and a registry.xml, describing the mapping of IPM message classes (say IPM.Note.Custom) to these formulas. Simple enough. And since aspx files are easy to develop, it should be a piece of cake to create a full-fledged solution.

So, here is the catch – To retain a single-sign on experience, all the forms have to be put in a directory beneath the directory C:\Program Files\Microsoft\Exchange Server\ClientAccess\Owa\forms. Then, a web-application has to be created that runs in the default OWA application pool (MSExchangeOWAAppPool). This way, OWA will handle all the authentication stuff and you can use it to call Exchange WebServices. The problem with this approach is this: OWA uses an HttpModule (Microsoft.Exchange.Clients.Owa.Core.OwaModule, implemented in the assembly Microsoft.Exchange.Clients.Owa.dll) that inspects every request that is made to a file beneath the /owa virtual directory. At least, every file that is controlled by the ASP.NET runtime. Any direct request will be rejected. This leads to two problems:

  1. When the custom form is rendered in the client browsers, the forms action attribute will point to something like “/owa/forms/customform/editform.aspx”. Any attempt to post back to this location will fail.
  2. ASP.NET uses a javascript to execute the post back. Even just a standard HTML button is used. But part of the required javascript is loaded from an external script. And since .NET 2.0, a handler called WebResource.axd is used to serve this script. Again, OWA will block any attempt to load this script.

The solution to the first problem is quite simple: ASP.NET allows the modification of the form tag from a code-behind file:

   1: protected override void OnLoad(EventArgs e)
   2: {
   3:     base.OnLoad(e);
   4:     if (Form.Action.IsNullOrEmpty())
   5:     {
   6:         Form.Action = "/owa/" + Request.Url.Query;
   7:     }
   8:     Response.Cache.SetExpires(DateTime.Now);
   9:     Response.Cache.SetLastModified(DateTime.Now);
  10: }

The important part is implemented in lines 4 to 7. This adjusts the action attribute of the form element to point to a direction OWA accepts. The lines 8 and 9 ensure that the form is always executed again. When omitted, OWA will gladly cache the files for quite some time – even if the underlying element changes.

The second problem does not have such an elegant solution. In fact, it now gets quite messy. Since OWA blocks access to the WebResource.axd handler, the only solution I found is to create a new web application project, start it up and manually download the script referenced in the standard aspx file. Once done, give the script a frindly name (something like DefaultScript.js) and put it in the folder of your custom forms and reference the script file from within your custom form with a <script> tag:

   1: <script language="javascript" src="/owa/forms/crmproject/DefaultScript.js"></script>
Far from nice, but it works.

Posted by Henning Krause on Monday, March 23, 2009 10:05 PM, last modified on Monday, November 29, 2010 7:18 AM
Permalink | Post RSSRSS comment feed