In The Mix

As a SharePoint architect I have the business behind me and the Developers and IT Pro on my shoulders.

InfoPath Task Forms Made Easy Part 2 November 27, 2009

Filed under: InfoPath,SharePoint — fmuntean @ 9:52 pm

In a previous post I have talked about an approach of transferring complex data between the workflow and the InfoPath task form.

Now in this post I will give you the implementation described before and give you instructions on how to install and use it.

Download the following IPTaskFormsMadeEasy.zip and extract it on your development machine. It contains all the necessary files to follow the steps described here.

General Description:

The idea here is to bypass the ItemMetadata.xml file and send the xml that the form will de-serialize and display.

For this I have created a new Content Type derived from the Out Of the Box InfoPath Content Type. The ID for this Content Type is “0x01080100C9C9515DE4E24001905074F980F93161”. When used this content Type will open the InfoPath Task Form but instead of processing the ItemMetadata.xml will read a special key value pair ("IPFormDataXML”) from ExtendedProperties that will contain the xml for that task. Once this task form gets closed the xml data for this task gets serialized back into the special key value pair to be read by the Workflow.

By using this approach we can pass quite complex data, as repeating tables, between the workflow and the task form without passing every value separately using the ItemMetadata.xml. Another benefit would be that you can now validate the data types using the task xsd and have data type safety when transferring information between the Workflow and the task form.

Installation:

Is quite simple to install this in your farm and does not affect any existing workflows as we are using our own content type.

Inside the zip file you will find the MFDWorkflowIPTask.wsp  SharePoint solution that you will need to install and deploy into your farm using the STSADM and or Central Admin site.  This will install a site collection feature that will enable a new content type (MFD.WorkFlowIPTaskCtype ContentType)
Now enable the MFD.WorkFlowIPTaskCtype feature on the site collection where you will be using Workflows that needs this content type and your done with the installation.

After this nothing actually happen until you are using the new content type into your workflow.

Developer Instructions:

Each time when this content type is used in Workflows the _layouts/MFD/WrkTaskIP.aspx page will be used instead of the OOB one (_layouts/WrkTaskIP.aspx).

I am not going to show here how you use the ItemMetadata.xml file to pass data between the workflow and the task form but I have included a demo with source code into the zip file, ApprovalWF1 project, that shows how to use the ItemMetadata.xml and ExtendedProperties. The demo uses just a single task form but imagine that you might have a complex workflow with over 10 or 20 tasks and you can see how hard is to maintain that code as changes are needed to the Task Forms.

The ApprovalWF2 demo project shows you how to use the new approach by passing the full xml to the task form and again being a demo I am just showing you how to implement it for a single task.

This Approval workflow deal with an Expense Report that contains complex data including repeating tables. Think about the following requirement where you are asked  that your workflow tasks needs to contain all the data from the original expense report so that the approver does not need to open the original report and the approvers can’t see other approvers notes during the approving process. If you want to know why you can’t use the Expense Report form and just add fields for each approver and just let them deal with that form drop me a line.

So now for the solution on how you implement this requirement.

First the forms, Expense Report Form and the the Task Form are both InfoPath forms. There are two ways of building InfoPath forms:

  1. Just start adding the fields as needed: very good for POC or if you don’t need much control over the fields namespace, schema and types.
  2. Start by thinking of the InfoPath like you do for you DB starting with the schema first by manually building your xsd files and then attach them to your InfoPath forms. This will let you control everything including the sharing of data types between multiple forms. This is how I recommend of building any Enterprise level InfoPath Form.

Under the Forms folder you have both, the Expense Report Form and ExpenseReportApproveTaskForm2, including the schema files. To include all the fields from the Expense Report Form (ERF) into the Task Form all you need to do is add the following tags:

   <xsd:import namespace="http://schemas.microsoft.com/office/infopath/2003/expXSD"
            schemaLocation="ExpenseReport.xsd"/> this will include all the fields defined into the ExpenseReport.xsd that is used by the Expense Report Form;

<xsd:element ref="exp:expenseReport" minOccurs="0"/> that will create an element into the ExpenseReportApproveTask2 Form for all the data included in the Expense Report Form.

Now having the xsd schema files for both of the forms we can actually generate two classes that will match that schema using:

        xsd.exe ExpenseReport.xsd ExpenseReportApproveTask.xsd /c
             /namespace:MFD.SharePoint.WorkFlow.Expenses.FormData

We will be using those two classes to serialize and de-serialize the xml data for both the Expense Form and Task Form.

Reading Expense Report Form inside workflow:

  • Reading Expense Report Form inside workflow:

    [NonSerialized]
    private expenseReport _expense;
    public expenseReport Expenses
    {
      get
      {
        if (_expense == null)
        {
          //Read the Form into memory
          XmlSerializer serializer = new XmlSerializer(typeof(expenseReport));
          using (Stream stream =  
                        this.workflowProperties.Item.File.OpenBinaryStream())
          { _expense = serializer.Deserialize(stream) as expenseReport; }
        }
      return _expense;
      }
    }

  • Create the Task:

    private void CreatingApproveTask(object sender, EventArgs e)
    {
      ApproveTaskId = Guid.NewGuid();
      ApproveTaskProperties.AssignedTo =
                 Expenses.manager.managerEmailAddress;
      ApproveTaskProperties.SendEmailNotification = true;
      ApproveTaskProperties.Title = string.Format("Approval for: {0}",
                  Expenses.employee.name);
      expenseReportApproveTask task = new expenseReportApproveTask();
      task.Decision = string.Empty;
      task.Notes = string.Empty;
      task.expenseReport = this.Expenses;
      ApproveTaskProperties.TaskType = 0;
      ApproveTaskProperties.ExtendedProperties[IPFormDataXMLTag] = 
                   Utility.Serialize(task);
    }

  • Read the Task:

    private void ApproveTaskChanged(object sender, ExternalDataEventArgs e)
    {
      string IPFormDataXML = this.ApproveTaskAfterProperties.ExtendedProperties 
                   [IPFormDataXMLTag] as string;
      expenseReportApproveTask task = Utility.Deserialize(IPFormDataXML);
      string taskDecision = task.Decision;
      isFinished = !string.IsNullOrEmpty(taskDecision);
      if (isFinished)
      {
        ApproveTaskOutcome = taskDecision;
      }
    }

This should give you an idea on how easy and clean is the code now. You will not have to change this code just because somebody else decided to the rename one of the fields in the Expense Report Form or even added a new field. The code will be the same what changes are the generated classes that will need to be refreshed but that is a recompilation matter not a code change.

The other thing that you should observe here is that we do not use strings anymore to pass data but the class itself which is strong typed so there is no more need of parsing the string into another type like Boolean and hope that nobody change the type on you.

Adding new Task Form, no problem, they follow the same pattern so adding another 10 or 20 forms to the Workflow is a breeze and reduce the spaghetti code needed to wire those up as you will have a different generated class for each.

The only thing that I did not show yet is how to use the new content type and that is easy, just modify the elements.xml for the workflow to specify that the tasks should use the new content type using the:
TaskListContentTypeId="0x01080100C9C9515DE4E24001905074F980F93161"

As you are going to deploy this is production i would recommend to add the MFD.WorkFlowIPTaskCtype feature as a dependency to your workflow feature by adding the following tag inside the Feature tag.
        <ActivationDependencies>
           <ActivationDependency FeatureId="33cf18b1-e091-46c2-9f52-114516731db7"/>
        </ActivationDependencies>

By doing this the system will automatically activate the dependency feature and will fail to activate your feature if the required feature is missing.

Hope this helps to clarify this approach but if not or need more info don’t hesitate to contact me or leave a comment.

Advertisements
 

11 Responses to “InfoPath Task Forms Made Easy Part 2”

  1. […] [Update November 2009] A follow up post with source code, demos and instructions for this approach is available here: https://fmuntean.wordpress.com/2009/11/27/infopath-task-forms-made-easy-part-2/ […]

  2. Nagarajan Palaniappan Says:

    Good Post, but i am facing error in installation of WSP,

  3. fmuntean Says:

    Please provide more info on the issue that you are facing by using the Contact Me link or posting a comment.

  4. pirione Says:

    Thank you very much, “Sei un grande”.

  5. malibeg Says:

    Hello. Great article. Did anybody tried this in SP 2010?

  6. fmuntean Says:

    Hi,

    Should not be any difference in this area between the two platforms. All you have to do is rebuild and deploy.

    Regards,
    Florin

  7. Jan Soucek Says:

    I’ve developed a few relative complicated state machine workflows for Sharepoint 2010 based on your idea described in your articles (https://fmuntean.wordpress.com/2009/11/27/infopath-task-forms-made-easy-part-2/ ). All works like a charm but I’ve one problem which I’m not able to resolve. This problem starts in case that I’ve Infopath task form with data connection from other Sharepoint list. In this case exchange information between Sharepoint and task form works through “_layouts/my_folder/wrktaskip.aspx“ and this works well. But data source is searched at original location („_layouts/wrktaskip.aspx“). How can I achieve to use wrktaskip.aspx in my folder from data connections?
    I would be very appreciated for your advice.
    Thanks a lot…
    Jan

  8. fmuntean Says:

    Maybe if you contact me using the “contact me” button on the main page we can continue this over email as I would need more info on the issue and maybe to take a look into your forms.

    Florin
    PS: in the mean time I have moved to SP203 and O365 and I am sure that you know that InfoPath is death.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s