Sharepoint Document Event Handlers

Over the last couple of days I’ve been putting together a prototype of a data intake and approval process using InfoPath and WSS Form Libraries.  Basically, I wanted to use InfoPath to be the front end and collect data that is stored in a Form Library.  As a result of the InfoPath Form being filled out and saved to the library, I wanted to utilize a custom Sharepoint Document Event Handler that would perform processing on the server.  For example, when the Form is inserted, I wanted to insert data into the Form (or XML file) on the server, and save it back into the Form Library.  The architecture from a high-level would look something like this:

 

 

  1. User clicks “Fill out Form” in the Sharepoint site to download the InfoPath Form template and fill it out.  After filling out the form, the user saves the completed form (XML file) to the Form Library. 
  2. Sharepoint then executes my custom event handler that opens up the XML Form file, de-serializes it into a set of objects, and performs processing using the data.
  3. The event handler updates data in the objects, serializes the objects to XML, and saves the updated XML file back to the Sharepoint Form Library.

So you might be thinking that’s pretty straight-forward.  Normally, developing Sharepoint Event Handlers and using them to process InfoPath Forms is straight-forward.  However, this situation represented a challenge because of step #3.  Specifically, when Sharepoint saves a file to a Form Library it will put a lock on the file and assign it a CheckedOutStatus of “short-term” (SPCheckOutStatus = ShortTerm).  Consequently, it was not possible for my Event Handler to update the form and save it back into the library.  One workaround would be to save the updated file with a different file name, but then I would need an application or process (manual or automated) to remove the original files that are saved in step #1.  Another workaround would be to use a queuing technology like MSMQ to queue the updates to the Form Library or use something like BizTalk 2004 and the BizTalk Adapter for Sharepoint to pull the file out of the library and insert it back later.  In this case BizTalk’s built-in support for configuring Send Port retries would provide me the ability to retry the save until the file lock is removed.  However, neither MSMQ nor BizTalk Server was an option in this situation due to other (non-technical) factors. 

 

Jan Tielens describes this problem and yet another, simpler workaround in his blog by forcing the current thread in the event handler to sleep until the file is no longer locked.  My concern with this approach was the reliability of the solution.  Should IIS be reset or the application pool recycled while an event handler was still executing, then the InfoPath form would never be saved by the event handler and the changes would be lost. 

 

In my opinion, this issue significant limits the useability of event handlers for Form Libraries.  I can think of several scenarios where you would want an event handler to be able to perform server side processing and update an InfoPath form.  Argh.

 

So I had to completely abandon the event handler approach and look into a different solution.  Instead of having the file saved back directly to Sharepoint, I configured the InfoPath template to submit the data to a custom Web Service. 

 

 

In this case, the custom WS would receive a complex type (set of serializable classes on the .NET side) that would contain the XML data for the Form.  The WS can then serialize the data to XML and use the Sharepoint .NET managed APIs to insert a new Form into the Forms Library. 

 

I’ve created a simple example based on the Service Request sample InfoPath Form that demonstrates this approach.  In this example, the Service Request form has been modified to submit data to a custom web service.  The custom web service modifies the received Service Request data and saves the data into a Form Library.  This example demonstrates the following:

 

  1. Submitting an InfoPath form to a custom Web Service

  2. Serializing & de-serializing an InfoPath Form to/from .NET classes

  3. Appending the XML processing instructions required by InfoPath to an XML document.

  4. Saving an XML document to a Sharepoint Forms Library using the WSS managed API.  

     

Download the sample and let me know your thoughts.