Using Word Automation Services in a Workflow custom activity for SP Designer Workflows

It has been quite sometime since I wrote any blog article.  What a way to start SharePoint 2010 blog about Workflows!!  It’s all about a new service named Word Automation Services which is a component of SharePoint Server 2010.  It provides developers the ability to perform document conversion tasks programmatically through the Word Automation Services application programming interface.

Supposedly we want to create an automation process that will convert bunch of word documents to PDF, XPS or any other format.  Once the conversion process is over, then move those documents to other repository.  For this we can create a custom workflow activity and then use this in SharePoint designer workflow.

In the custom activity Execute method, use ConversionJob class - https://msdn.microsoft.com/en-us/library/microsoft.office.word.server.conversions.conversionjob.aspx.  Make sure that in Central Administration, Word Automation Services is running.

Code Sample:

 private ConversionJob job = null;
  
 [Description("WordAutamtionServiceInstanctNameProperty")]
 [ValidationOption(ValidationOption.Optional)]
 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
 [BrowsableAttribute(true)]
 [CategoryAttribute("Parameter")]
 public String WordAutamtionServiceInstanctName
 {
    get
    {
      return ((System.String)(base.GetValue(WordAutamtionServiceInstanctNameProperty)));
    }
    set
    {
      base.SetValue(WordAutamtionServiceInstanctNameProperty, value);
    }
 }
  
 protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
 {
   StartConvertionJob(executionContext);
   // Check if the file is converted
   if (Converted)
   {
     //MoveFileToRepository.
     return ActivityExecutionStatus.Closed;
   }
   else
   {
    //Register in WorkflowQueuingService and wait.
    return ActivityExecutionStatus.Executing;
   }
 }
  
 private void StartConvertionJob(ActivityExecutionContext executionContext)
       {
            try
            {
                if (__Context.Site.SiteSubscription != null)
                    siteSubscriptionId = __Context.Site.SiteSubscription.Id;
                SPWeb web = __Context.Web;
                SPList list = web.Lists[this.listID];
                SPListItem listItem = this.workflowContext.GetListItem(list, this.listItemKey);
                job = new ConversionJob(WordAutamtionServiceInstanctName);
                job.UserToken = __Context.Site.UserToken;
                job.Settings.OutputFormat = Utility.GetSaveFormat(this.FileType);
                job.Settings.OutputSaveBehavior = SaveBehavior.AppendIfPossible;
                job.Settings.FixedFormatSettings.IncludeDocumentProperties = true;
                job.Settings.FixedFormatSettings.IncludeDocumentStructure = true;
                job.Settings.FixedFormatSettings.UsePDFA = true;
                job.Settings.UpdateFields = true;
                sourceFileUrl = String.Format("{0}/{1}", web.Url, listItem.Url);
                sourceFileExt = Path.GetExtension(sourceFileUrl);
                convertedFileUrl = Path.ChangeExtension(sourceFileUrl, FileType);
                job.AddFile(sourceFileUrl, convertedFileUrl);
                job.Name = Path.GetFileNameWithoutExtension(listItem.Name);
                jobId = job.JobId;
                job.Start();
           }
            catch (Exception ex)
            {
                //Exception logging.
            }
        }

 

Once we have custom activity built, we need to use it in SharePoint Designer workflow.  For this build custom action file and deploy it under ..\14\TEMPLATE\1033\Workflow location

 <RuleDesigner Sentence="Convert document to %1 file type and submit it to %2 with %3( %4 of converted document)">
 <FieldBind Field="FileType" DesignerType="Dropdown" Id="1" Text="PDF">
   <Option Name="PDF" Value="PDF"/>
   <Option Name="XPS" Value="XPS"/>
   <Option Name="DOCX" Value="DOCX"/>
   <Option Name="DOCM" Value="DOCM"/>
   <Option Name="DOC" Value="DOC"/>
   <Option Name="DOTX" Value="DOTX"/>
   <Option Name="DOTM" Value="DOTM"/>
   <Option Name="DOT" Value="DOT"/>
   <Option Name="XML" Value="XML"/>
   <Option Name="RTF" Value="RTF"/>
   <Option Name="MHT" Value="MHT"/>
 </FieldBind>
 <FieldBind Field="Destination" Text="this destination router" Id="2" DesignerType="TextArea" />
 <FieldBind Field="Explanation" Text="this explanation" Id="3" DesignerType="TextArea" />
 <FieldBind Field="ReturnResult" Text="submit file result" Id="4" DesignerType="ParameterNames" />
 RuleDesigner>

In SharePoint Designer, create a list workflow and choose this custom activity.

image

In the destination router, choose the Web Service URL that we get from Content Organizer Settings in the site.  More details about Content Organizer, https://msdn.microsoft.com/en-us/library/ee558288.aspx.  Deploy the workflow in a SharePoint list and the document conversion will happen and then moved to the respective repository.

 

image

image

Caveat using ConversionJob:

In the Execute method of the activity, if the file is not converted (file is null), it moves to else loop wherein we return the activity status as “Executing” i.e ActivityExecutionStatus.Executing.  At this point, the workflow instance has no runnable work and is therefore considered idle. At idle-time, the workflow runtime will attempt to persist the state of the workflow instance using a host-provided persistence service.  When a workflow instance is idle, its state may be serialized to a host-provided store and removed from memory.  Later, The serialized state of the workflow instance can be used to reactivate the instance in memory, at which point the instance is restored to its state and is available to do work.

When the workflow tries to persist the data, we might end up getting this errror, “Unable to serialize workflow, exception: Type 'Microsoft.Office.Word.Server.Conversions.ConversionJob' in Assembly 'Microsoft.Office.Word.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' is not marked as serializable”.  The reason we get this error is as would have already guessed, the class 'Microsoft.Office.Word.Server.Conversions.ConversionJob' is not marked as serializable.  So, make sure that any instance of ConversionJob is not declared at class level (as serialization could happen).  So use this class only within the respective methods and then dispose them accordingly.