Ensuring Infopath forms to open in Forms Services

You might have ran into the following issue; you've deployed your InfoPath forms to Forms Services, and (of course) it seems to works like a charm.

It seems? Yes, there some exceptions in which case Forms Services does not do what you expect it to do, for example:

- Opening a form from the Search results
- Opening a form from a link (in an email, spreadsheet export, Content Query Webpart or anywhere else)

In these cases you'll notice that the form will try to open in the Infopath client application instead of the browser. The reason is that you're missing some smart javascript that is triggered when you click the link. This script is embedded in the Forms Library views, and redirects you to the browser version of the form.

 The box asking you to open the form in the client

We've created a catch all solution that is quite easy to implement as well. It's based on a HTTP Module that will pick up every request and check whether it's a request for an Infopath Forms Services document. If yes, it redirects the user to the equivalent page that renders the browser version of the form.

The HTTP Module looks like this (sorry about the empty lines, could not get rid of them..):

   1:  /// <summary>
   2:  
   3:      /// Checks whether this is a call to a web-enabled InfoPath form which should be opened in Forms Services
   4:  
   5:      /// </summary>
   6:  
   7:      public class DisplayFormInBrowserHandler : IHttpModule
   8:  
   9:      {
  10:  
  11:  
  12:  
  13:          /// <summary>
  14:  
  15:          /// Attach the PreRequestHandlerExecute event
  16:  
  17:          /// </summary>
  18:  
  19:          /// <param name="context"></param>
  20:  
  21:          public void Init(HttpApplication context)
  22:  
  23:          {
  24:  
  25:              context.PreRequestHandlerExecute += PreRequestHandlerExecute;
  26:  
  27:          }
  28:  
  29:  
  30:  
  31:          /// <summary>
  32:  
  33:          /// Attach the PreInit event
  34:  
  35:          /// </summary>
  36:  
  37:          /// <param name="sender"></param>
  38:  
  39:          /// <param name="e"></param>
  40:  
  41:          static void PreRequestHandlerExecute(object sender, EventArgs e)
  42:  
  43:          {
  44:  
  45:              Page page = HttpContext.Current.CurrentHandler as Page;
  46:  
  47:  
  48:  
  49:              if (page != null) // check if this is a page or document
  50:  
  51:              {
  52:  
  53:                  page.PreInit += PreInit;
  54:  
  55:              }
  56:  
  57:          }
  58:  
  59:  
  60:  
  61:          /// <summary>
  62:  
  63:          /// Checks whether this request should be redirected to Forms Services
  64:  
  65:          /// </summary>
  66:  
  67:          /// <param name="sender"></param>
  68:  
  69:          /// <param name="e"></param>
  70:  
  71:          static void PreInit(object sender, EventArgs e)
  72:  
  73:          {
  74:  
  75:              try
  76:  
  77:              {
  78:  
  79:                  Page page = (Page)sender;
  80:  
  81:  
  82:  
  83:                  // Check whether this is an Infopath form and whethers it's not already opening in Forms Services
  84:  
  85:                  if (page.GetType().ToString().ToLower(CultureInfo.InvariantCulture).Contains("formserver") &amp;&amp; !page.ClientQueryString.Contains("DefaultItemOpen"))
  86:  
  87:                  {
  88:  
  89:                      string url = string.Format("http://{0}{1}&DefaultItemOpen=1", page.Request.Url.Host, page.Request.RawUrl);
  90:  
  91:                      page.Response.Redirect(url, false);
  92:  
  93:                  }
  94:  
  95:              }
  96:  
  97:              catch (Exception ex)
  98:  
  99:              {
 100:  
 101:                  ExceptionPublisher.PublishInternalException(ex);
 102:  
 103:              }
 104:  
 105:          }
 106:  
 107:  
 108:  
 109:          public void Dispose() // nothing to dispose here
 110:  
 111:          {
 112:  
 113:          }
 114:  
 115:      }

You'll need to register the event-handler in the web.config to enable it. You can do this manually or use the following code. I'm calling it from a simple feature, but that's up to you to implement.

   1:          /// <summary>
   2:  
   3:          /// Adjust the web.config to use the HttpHandler to make sure that all 
   4:  
   5:          /// InfoPath forms are opened in the browser instead of the client.
   6:  
   7:          /// </summary>
   8:  
   9:          /// <param name="webApp">The web application</param>
  10:  
  11:          /// <param name="add">Add or remove the HttpHandler to/from the web.config</param>
  12:  
  13:          public static void ActivateDesignFeatureForWebApp(SPWebApplication webApp, bool add)
  14:  
  15:          {
  16:  
  17:              //Add ore remove the HTTPHandler to redirect a page that tries to open an InfoPath form 
  18:  
  19:              //in the InfoPath client
  20:  
  21:              switch (add)
  22:  
  23:              {
  24:  
  25:                  case true:
  26:  
  27:                      webApp.WebConfigModifications.Add(CreateHttpModuleModification());
  28:  
  29:                      break;
  30:  
  31:                  case false:
  32:  
  33:                      webApp.WebConfigModifications.Remove(CreateHttpModuleModification());
  34:  
  35:                      break;
  36:  
  37:              }
  38:  
  39:  
  40:  
  41:              webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
  42:  
  43:              webApp.Update();
  44:  
  45:          }
  46:  
  47:  
  48:  
  49:          /// <summary>
  50:  
  51:          /// Creates the SPWebConfigModification for the HTTPHandler
  52:  
  53:          /// </summary>
  54:  
  55:          /// <returns></returns>
  56:  
  57:          private static SPWebConfigModification CreateHttpModuleModification()
  58:  
  59:          {
  60:  
  61:              string ModName = "add[@name='DisplayFormInBrowserHandler']";
  62:  
  63:              // modName must be equal to the name attribute of the childnode!
  64:  
  65:              string ModXPath = "configuration/system.web/httpModules";
  66:  
  67:  
  68:  
  69:              SPWebConfigModification modification = new SPWebConfigModification(ModName, ModXPath);
  70:  
  71:              modification.Owner = "[Admin name]";
  72:  
  73:              modification.Sequence = 0;
  74:  
  75:              modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
  76:  
  77:              modification.Value =
  78:  
  79:                  @"<add name=""DisplayFormInBrowserHandler"" type=""[Namespace].DisplayFormInBrowserHandler, [Namespace], Version=[1.0.0.0], Culture=neutral, PublicKeyToken=[1234567890.]"" />";
  80:  
  81:              return modification;
  82:  
  83:          }

Don't forget to replace the [brackets].

One important aspect of this solution is whether it is supported. I've been hearing different stories about using HTTP Modules in SharePoint, some say they are supported, other say they're not. Please keep that in mind if you're dealing with MS support – disabling the module should be good enough.

Leave a Reply