DevExpertise

Practical tips and tricks for all things .NET, SharePoint, Silverlight, InfoPath, and general application development.

Archive for July, 2009

Fixing the "Selected file was not found” Error When Adding an Attachment to an InfoPath Workflow Task Form

Posted by DevExpert on 1st July 2009

If you’re at all familiar with creating Visual Studio-authored workflows for SharePoint, you’re probably aware that you can also create custom task forms for tasks that have been assigned in that workflow.  The task forms can either be implemented as ASP.NET forms or InfoPath forms. My personal preference is InfoPath, provided the functionality that is needed can be accomplished using InfoPath.  By choosing InfoPath, much of the overhead required to allow SharePoint to use it as a task form is already done, whereas with ASP.NET it’s up to the developer to implement.

On a recent project, I had a need to create a workflow that at a certain step, prompted the user to upload a file attachment.  InfoPath was the obvious choice because they’re simple to create, simple to deploy, and they even support attachments.  After creating the form and the workflow I tried attaching a file to the InfoPath task form, and received the following error message:

 image

I searched around a little and found that this is a known issue, and there are a few ways to fix it.  This post suggests adding the following bit of JavaScript to the WrkTaskIP.aspx page, which is responsible for hosting the InfoPath task form:

<script type="text/javascript">
    aspnetForm.encoding = "multipart/form-data";
</script>

Another approach documented here suggests modifying the application.master master page file to add the necessary enctype form tag:

<form runat="server" onsubmit="return _spFormOnSubmitWrapper();" enctype="multipart/form-data">
  ...
</form

While both of these approaches work, I wasn’t completely happy with modifying out-of-the-box SharePoint files, which isn’t recommended anyways.  I took a slightly more involved, but much more reusable approach. Any customization you make to SharePoint really should be implemented as a Feature.  I’m not going to go into the nuts and bolts of what features are, but you can learn a little more about them from this previous post.  Before I explain my approach, here are your options for accomplishing this:

  1. Modify the out-of-the-box application.master master page file on the file system.  Not recommended.
  2. Modify the out-of-the-box WrkTaskIP.aspx page on the file system.  Not recommended.
  3. Create a new task content type, create a copy of WrkTaskIP.aspx and rename it, add the JavaScript to that page, associate the new ASPX page to your new content type, then point your workflow task forms to that new content type.  Not impossible, better than the above approaches, but still a lot of unnecessary work.
  4. Create a user control with the necessary script and deploy it as a delegate control feature.  Recommend, and the approach I describe in this post.

I decided to go with JavaScript, because I knew I could insert that into a page a lot easier than I could insert a form tag attribute.  Using an approach I’ve used before on previous projects, I decided to implement this using the delegate control pattern.  Take a look here and here first for a primer on delegate controls, but basically what they allow you to do is insert custom user or server controls into a place holder in the master page using a feature.  This is perfect, because you can add functionality to all site pages immediately without actually modifying a single page.

The first step is creating the user control that will be responsible for adding the encoding to the form.  I took a little different approach here too, and used jQuery to attach the encoding element to the forms. Obviously this implies that the jQuery library is being referenced already.  There are other solutions that make this a cinch to accomplish, such as this one by the great Jan Tielens.  In fact, this solution uses the exact same approach that I’m blogging about here.  My DevExpertise.TaskFormEncoding.ascx user control looks like this:

<%@ Control Language="C#" ClassName="DevExpertiseTaskFormEncoding" %>
<script type="text/javascript" >
    $(document).ready(function() {
        $("form").each(function(i) {
            this.encoding = "multipart/form-data";
        });
    });
</script>

Now that I have the user control created, I need to create a SharePoint feature to insert this into a delegate control placeholder.  Both the default.master page and application.master pages that SharePoint use by default have a delegate control named AdditionalPageHead, which is there specifically for this purpose – to add script, CSS references, etc. to the page’s HEAD section:

<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true"/>

The following snippet is my feature.xml file, which defines the feature.  This file is responsible for specifying the feature ID, Title, Description, etc., plus any element manifests that our feature requires:

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="2D597698-5FBC-482a-BA0F-2E42DEA2E8E4"
         Title="DevExpertise InfoPath Workflow Task Form Encoding"
         Description="Adds the necessary form encoding to allow attachments
                      to be added to InfoPath workflow task forms."
         Scope="Site"
         Version="1.0.0.0"
         ImageUrl="DevExpertise\devexpertiseLogo.png"> 

  <ElementManifests>
    <ElementManifest Location="elements.xml" />
  </ElementManifests>
</Feature>

This feature is expecting an elements.xml manifest file, which is responsible for wiring up my custom user control to the AdditionalPageHead delegate control in the master page:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control
    Id="AdditionalPageHead"
    ControlSrc="~/_controltemplates/DevExpertise/DevExpertise.TaskFormEncoding.ascx"
    Sequence="10"/>
</Elements>

The only thing left is packaging everything up and deploying it. I always package my features up into solution packages using WSPBuilder, since a solution package can be used to deploy other feature-dependant files to SharePoint’s 12 folder structure. My entire solution folder structure looks like this:

image

Create the solution package, deploy it to SharePoint, and you will have a site collection feature ready for activation:

image

That’s it!  Now you can successfully add attachments:

image

You may be asking yourself why I went through all that trouble just to add a couple lines of JavaScript to my pages, when I could’ve just opened application.master and thrown it in there.  Well, it’s not a recommended best practice to modify system files.  If an update or service pack is installed that overwrites these files, then all your modifications are gone.  In addition, a change like that would have to be made to all web front-end servers in your farm.  This approach is extremely reusable – I can take this solution package and activate it in any site collection in any farm and I have the necessary functionality.

I’m feeling generous today and decided to include the solution package for your downloading pleasure.  As always, it comes as-is and without warranty:

Tags: , , , , ,
Posted in InfoPath, JQuery, JavaScript, SharePoint, Workflow | 2 Comments »