18 May 2011

Starting a workflow for the current InfoPath form item in code behind

If you have the requirement to be able to programmatically start a workflow from the code behind an InfoPath form template, then the following code might do the trick (which can be called say from a button click event).

You'll need to have a promoted field in your form template which stores a unique ID for the current form item. You can use the core ID field value provided by SharePoint or perhaps you generate your own unique reference number for the form, whichever you use it needs to uniquely identify the form in the library so we can get the current form item from code using SPQeury and can then spark off the workflow.




private bool StartWorkflow(SPContext ctx)
{
    bool restarted = false;
    string output = "";
    try
    {
        SPList myForms = ctx.Web.Lists["My Forms Library"];
        if (myForms != null)
        {

            ctx.Web.AllowUnsafeUpdates = true;
            SPListItem thisForm = GetCurrentListItem(myForms);
            if (thisForm != null)
            {
                // Get the workflow association template using the workflow name as displayed on the workflow setting page
                SPWorkflowAssociation associationTemplate = prForms.WorkflowAssociations.GetAssociationByName("My Workflow", System.Globalization.CultureInfo.CurrentCulture);
                if (associationTemplate != null)
                {
                    // Now try and start the workflow
                    SPWorkflow newWorkflow = ctx.Site.WorkflowManager.StartWorkflow(thisForm, associationTemplate, associationTemplate.AssociationData);
                    if (newWorkflow != null)
                    {
                        // Success
                        restarted = true;
                    }
                }
            }
        }
    }
    catch (Exception) { }

    return restarted;
}

private SPListItem GetCurrentListItem(SPList myForms)
{
    SPListItem currentItem = null;
    // Get unique ID of current form from a field in form template
    // This ID field must be promoted to the SharePoint list
    string itemId = GetFormFieldValue("/my:myFields/my:MyFormID");
    if (itemId != null && !itemId.Equals(""))
    {
        if (myForms != null)
        {
            SPQuery oQuery = new SPQuery();
            // Query the forms library to get the item where the unique form ID field equals itemId
            // Use the internal field name in the where clause!
            oQuery.Query = string.Format(
                    "{0}"
                    , itemId);
            oQuery.ViewFields = "";
            SPListItemCollection collListItems = prForms.GetItems(oQuery);
            if (collListItems != null && collListItems.Count > 0)
            {
                foreach (SPListItem oListItem in collListItems)
                {
                    // Should only be one result
                    currentItem = oListItem;
                    break;
                }
            }
        }
    }

    return currentItem;
}

private string GetFormFieldValue(string xPath)
{
    XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();
    XPathNavigator xnMyField = xnDoc.SelectSingleNode(xPath, this.NamespaceManager);
    if (xnMyField != null)
    {
        return xnMyField.Value;
    }
    else
    {
        return string.Empty;
    }
}
   

Using Federated Search to display Autonomy results

Our main intranet search engine is Autonomy and our company have spent a great deal of effort and money to get Autonomy to index SharePoint content using the Autonomy SharePoint Connector product.

What they didn't do is think about how we could reverse the scenario and provide autonomy search results within SharePoint. So, my first thought was along the lines of a custom development project but quickly realised it actually takes about 5 minutes to setup using SharePoint Federated Search feature...

Step 1 - Setup the federated search location

  1. In Central Admin go to 'Manage Service Applications'
  2. Click your 'Search Service' application to take you to the 'Search Administration' page
  3. Click 'Federated Locations' on the left menu
  4. Click 'New Location'
  5. Enter a logical Name like "Autonomy Production", Display Name and Description
  6. Author and Version fields are optional
  7. Leave the 'Trigger' field set to 'Always' unless you which to only search Autonomy when a certain prefix is added to the search term
  8. Expand the 'Location Information' section
  9. Select 'OpenSearch 1.0/1.1' in the 'Location Type' field
  10. Enter your Autonomy search URL in to the 'Query Template' field including the {searchTerms} parameter e.g. http://autonomy.company.com:9000/a=query&text={searchTerms}&maxresults=10&printfields=DRETITLE,DRETITLEURL
  11. Note I have applied a 'maxresults' parameter which you may wish to change. I have also added the 'printfields' to ensure that we return the correct title and title URL field for each result. DO NOT change the value of the 'printfields' parameter unless you are confident at modifying XSLT (which comes later).
  12. Enter the same URL as above into the '"More Results" Link Template' field
  13. Expand the 'Display Information' section
  14. Uncheck the 'Use Default Formatting' checkbox
  15. Click inside the top text field labelled 'XSL' and delete the existing content using ctrl+a > Delete
  16. Now paste the XSL shown at the bottom of this post into the blank textbox (you might want to paste it into a XML editor first to clear up any pointless whitespace added by the RTE!)
  17. Leave the remaining textbox contents as they are
  18. Expand the 'Restrictions and Credentials Information' section
  19. Leave the 'Restrict Usage' field set to 'No Restrictions' unless you wish to specify a particular search site that is allowed to use this federated location
  20. Now select the access credentials relevant to your environment, I use a service account so have selected "NTLM - Specify a username and password" option
  21. Now click OK
  22. You will be alerted to any fields that you've missed or if the XSL cannot be parsed, but if you end up back at the federated locations list and our new location is listed then we are nearly there!
Step 2 - Test Autonomy results using the Federated Search web part

  1. Go to any one of your site collections (or the one specified in the "Restrict Usage" section if appropriate)
  2. Create a test page on your site
  3. Click the Page tab and select 'Edit' from the ribbon
  4. Add a 'Search Box' web part to the page
  5. Click 'Edit Web Part' from the web part's context menu
  6. Expand the 'Miscellaneous' section and in the 'Target search results page URL' field enter the full URL of the current page (our test page) e.g. /somesite/SitePages/test.aspx
  7. Click OK
  8. No add a 'Federated Search' web part to the page benath the search box web part
  9. Click Edit Web Part from the web part's context menu
  10. From the 'Location Properties' drop down list select your 'Autonomy' location
  11. Click OK
  12. Click Save and Exit to save the test page
  13. Now enter a search term into the search box and hit enter
  14. You should see your Autonomy results appear in the federated search web part. The results are presented in a very basic text format, if you wish to modify the way the results appear you'll need to change the XSLT
XSL to paste at point 16:


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:autn="http://schemas.autonomy.com/aci/" exclude-result-prefixes="autn">
<xsl:output method="html" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="autnresponse">
<xsl:apply-templates select="responsedata" />
</xsl:template>
<xsl:template match="responsedata">
<table border="0">
<xsl:apply-templates select="autn:hit" />
</table>
</xsl:template>
<xsl:template match="autn:hit">
<xsl:apply-templates select="autn:content" />
</xsl:template>
<xsl:template match="autn:content">
<tr>
<td>
<a>
<xsl:attribute name="href">
<xsl:value-of select="DOCUMENT/AUTONOMY/DRETITLEURL" />
</xsl:attribute>
<xsl:value-of select="DOCUMENT/AUTONOMY/CONTENT_TITLES/DRETITLE" />
</a>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>