Word Automation Services: Solution Sample (Workflow)

In the Word Automation Services: What It Does post, I provided a very high-level outline of the server-side API provided by the service, showing you the basic outline for working with the service:

  • Create a ConversionJob
  • Provide it the settings for the conversion(s) to perform
    • User credentials to fetch/store files
    • Target file format for output
    • Etc.
  • Tell it while file(s) to process
  • Start
  • (optionally) Monitor progress

In this post, I wanted to look at a specific example solution and what's involved in creating it, to walk through a real example of the service end-to-end.

The Scenario

In this example, I have a library in which I store contracts as they're being written. Once they're approved, I set the Status property for that document within the library to "Final" and an XPS version of it is automatically generated to archive the agreed-upon version of the content.

Creating the Solution

I've written up the solution in tutorial form, so folks w/ Visual Studio 2010 and SharePoint 2010 can actually build the resulting workflow; if that's not your goal, browsing the sample code should be enough to give you an idea of how the solution works.

Set up the Document Content Type

Before we start, we add the Status column to the Document content type, so that we can use it in this walkthrough.

  1. From the SharePoint site, choose Site Actions (in the upper-left hand corner), then click Site Settings.
  2. Under the Galleries heading, choose Site Content Types.
  3. Click on Document to edit its content type.
  4. Choose Add from existing site columns.
  5. In the Available Columns list, find Status and click Add to add it to the list of columns to add. Note: If Status cannot be found, it may already have been added to the content type.
  6. Click OK.

Creating the Project

First, we create a SharePoint project in Visual Studio which will contain our workflow code.

  1. Start Visual Studio 2010 as an administrator. Note: You must start Visual Studio as an administrator in order to successfully publish the project to the SharePoint farm.
  2. Under the File menu, choose New, and then Project…
  3. In the New Project dialog box, select the Visual C# SharePoint 2010 project type.
  4. Select Sequential Workflow from the template list.
  5. Give the project a name (e.g. ArchiveDocument).
  6. Click OK to create the project.
  7. When asked, choose to Deploy as a farm solution. Note: This is required because the Word Automation Services object model cannot be accessed from partially trusted code.
  8. On the next step, give the workflow a friendly name, e.g. "Archive Document" and choose List Workflow as the workflow type.
  9. Leave the default association settings, and click Next. Note: If you want to attach the workflow to a specific list, change the List drop-down to that list. In this tutorial, we will use the default Shared Documents list on the SharePoint site.
  10. Uncheck "On item creation" in the default settings for workflow initiation (leaving "Manually" as the only selected value), and click Finish.

At this stage, we now have a new empty workflow project.

Add Reference to the Word Automation Services Object Model

To perform conversions, we need to include a reference to the Word Automation Services object model.

  1. From the Solution Explorer window, right-click on References and choose Add Reference…
  2. Browse to find the reference using the Browse tab. The Microsoft.Office.Word.Server.dll assembly is located in the SharePoint Server 2010 ISAPI folder, typically located at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI.

    Add Reference Dialog Box

  3. Click OK to add the reference.

Note: If you receive a warning that the DLL requires a newer version of the .NET Framework, choose Yes to add the reference anyway. Then, add a reference to System.Web.DataVisualization, typically located at C:\windows\Assembly\GAC_MSIL\System.Web.DataVisualization\3.5.0.0__31bf3856ad364e35\.

Design the Workflow

Now that we have a workflow project, we will add a two-step workflow: the first step checks whether the Status property has been set to "Final"; once it has, the second step converts the document.

Step 1: Check the Status Property

  1. From the Toolbox, under Windows Workflow v3.0, add a While activity after the existing onWorkflowActivated activity.
  2. From the Toolbox, under SharePoint Workflow, add an OnWorkflowItemChanged activity inside the While activity.
  3. Click on the OnWorkflowItemChanged activity. From the Properties window, set the value of the CorrelationToken property to workflowToken (the sole item in the drop-down list).

    CorrelationToken property

    This tells the activity the information necessary to associate the ItemChanged event with the correct workflow.

  4. From the Properties window, click on the lightning bolt to switch to Events view, and press ENTER in the Invoked method to create a blank event handler. This event handler will be triggered whenever the item changes.
  5. In the code window, add a global Boolean value to track whether the Status property has been set to the desired value:

    bool documentReady = false;

  6. In the event handler, add code to check the value of the column, and set the documentReady variable appropriately:

    //check if the Status is set to final; if so, the document is ready to archive
    if (workflowProperties.Item["Status"] != null)
    {
       
    _documentReady = ((string)workflowProperties.Item["Status"] == "Final");
    }

  7. Switch back to the workflow designer window. Note: It will have a name like Workflow.cs [Design].
  8. Click on the While activity. From the properties window, click on Condition and choose Declarative Rule Condition.
  9. Expand the Condition field, exposing ConditionName and Expression:

  10. In the ConditionName field, give the condition a name, e.g. Ready to Archive.
  11. Click in the Expression field, and press the  button to set the condition.
  12. In the dialog box, type the following condition:

    documentReady == false

  13. Click OK to save the condition.

The resulting workflow now looks like:

Step 2: Convert the Document

Now that we've created the portion of the workflow that waits for the column value to be set to Final, we add the workflow activity to actually convert the document.

  1. From the Toolbox, under Windows Workflow v3.0, add a Code activity after the existing While activity.
  2. From the Properties window, click on the lightning bolt to switch to Events view, and press ENTER in the ExecuteCode method to create a blank event handler. This event handler will be triggered whenever the item changes.
  3. In the event handler, add code to perform the conversion:

    //create a conversion job
    ConversionJob job = new ConversionJob("Word Automation Services");

    //specify conversion settings
    job.UserToken = workflowProperties.OriginatorUser.UserToken;
    if (workflowProperties.Site.SiteSubscription != null)
        job.SubscriptionId = workflowProperties.Site.SiteSubscription.Id;
    job.Settings.OutputFormat = SaveFormat.XPS;
    job.Name = "Archive Document Workflow";

    //add the file
    string fileUrl = workflowProperties.WebUrl + "/" + workflowProperties.ItemUrl;
    job.AddFile(fileUrl, Path.ChangeExtension(fileUrl, "xps"));

    //schedule the conversion
    job.Start();

  4. This code creates a new ConversionJob, which defines a set of conversions, supplying the name of the service application. Note: This example assumes the name of the service application is "Word Automation Services", which is the default name when it is created via the Farm Configuration Wizard. If you have used a different name for the service application, change the name as appropriate.

    Then, we set the necessary settings for the conversion:

  • The UserToken property, which specifies the user credentials used to read the input file and write the output file.
  • The SubscriptionId property, which specifies the site subscription ID of the site. Note: This parameter is only required if the SharePoint farm has been configured in partitioned mode.
  • The OutputFormat property, which specifies the output file format for the conversion.

As well, we specify one optional setting:

  • The Name property, which specifies a friendly name for the conversion.

Next, we add the file to the conversion job via the AddFile method, and start the processing of the conversion using the Start method.

The resulting workflow now looks like:

    

(Optional) Step 3: Monitor the Conversion

Once we've scheduled the conversion, it is processed asynchronously. Finally, we can add a step to monitor the result of the conversion before terminating the workflow, so that the workflow completes after the conversion.

  1. From the Toolbox, under Windows Workflow v3.0, add a While activity after the existing codeActivity activity.
  2. From the Toolbox, under Windows Workflow v3.0, add a Sequence activity inside the While activity.
  3. From the Toolbox, under Windows Workflow v3.0, add a Delay activity inside the Sequence activity.
  4. Click on the new codeActivity activity. From the Properties window, click on the TimeoutDuration property and set it to 00:00:30 (30 seconds). This means that the workflow will be re-checked at most every 30 seconds. Note: Because delays in SharePoint workflows are processed using a timer job with a default frequency of 5 minutes, it may take up to 4:59 for the delay to be processed.
  5. From the Toolbox, under Windows Workflow v3.0, add a Code activity after the Delay activity.
  6. Click on the new codeActivity activity. From the Properties window, click on the lightning bolt to switch to Events view, and press ENTER in the ExecuteCode method to create a blank event handler. This event handler will be triggered whenever the item changes.
  7. In the code window, add two global variables: a Guid value to store the ID of the conversion, so that we can check it on regular intervals, and a Boolean to track whether the conversion completed successfully:

    Guid jobId;
    bool conversionComplete = false;

  8. In the first code method, store the ID of the conversion job into this global variable, by adding the following code after the Start method:

    //save the job's ID
    jobId = job.JobId;

  9. In the new event handler (created in Step 6), add code to check the status of the conversion:

    //monitor the conversion
    //get the site subscription ID
    Guid? siteSubscription = null;
    if (workflowProperties.Site.SiteSubscription != null)
       
    siteSubscription = workflowProperties.Site.SiteSubscription.Id;

    //check if the conversion is complete; if it is, refresh
    ConversionJobStatus status = new ConversionJobStatus("Word Automation Services", jobId, siteSubscription);
    if (status.Count == status.Succeeded)
    {
       
    //success!
       
    conversionComplete = true;
    }
    else if (status.Count == status.Failed)
    {
       
    //conversion failed
       
    ReadOnlyCollection<ConversionItemInfo> failedItems = status.GetItems(ItemTypes.Failed);
       
    throw new Exception(failedItems[0].ErrorMessage);
    }
    else if (status.Count == status.Canceled)

       
    //conversion was canceled
        throw new Exception("Conversion was canceled.");
    }

    //since we didn't finish, keep waiting

    This code checks the status of the conversion using the ConversionJobStatus object. Note: This example assumes the name of the service application is "Word Automation Services", which is the default name when it is created via the Farm Configuration Wizard. If you have used a different name for the service application, change the name as appropriate.

    Once we have the status for the job, we can check whether the item has succeeded or failed, and react accordingly. Otherwise, we do nothing, since the conversion is still in progress.

  10. Switch back to the workflow designer window. Note: It will have a name like Workflow.cs [Design].
  11. Click on the While activity. From the properties window, click on Condition and choose Declarative Rule Condition.
  12. Expand the Condition field, exposing ConditionName and Expression:

  13. In the ConditionName field, give the condition a name, e.g. Conversion Complete.
  14. Click in the Expression field, and press the  button to set the condition.
  15. In the dialog box, type the following condition:

    conversionComplete == false

  16. Click OK to save the condition.

The final workflow should look like this:

Build and Deploy the Solution

Now, deploy the solution to your SharePoint farm.

  1. On the Build menu, choose Deploy Solution to build the code and deploy it to SharePoint.
  2. From the Shared Documents library (or whichever library you chose in Step 9 of Creating the Project), upload a new Word document to start the workflow.
  3. Right-click on the new document and choose Workflows.
  4. Click on Archive Document to start the workflow.
  5. Right-click on the new document and choose Edit Properties.
  6. Set the Status property to Final.
  7. Press OK.

When the timer job runs and the conversion is processed, you should see the XPS file appear next to the original document (refresh the page to see the result). Note: Again, because the conversions are processed using a timer job, it may take up to the frequency of the timer job for the file to appear.

Office Blogs Comments

Comments: (5) Collapse

  • Will a set of WF-activities be supplied for Word Automation Services? Since Code-activities are no longer possible (kind of) in WF4, a future migration is probably required, while it would not be if a standard activity would be supplied (and in the future a WF4-version).

  • אני צריכה את זה בשביל משימות שנותנים לי מהבית ספר ובשביך להדפיס דרך זה עבודות

  • Sorry this is offtopic and unrelated to the blog post (as the Word team blog has no "Email" link like other Office blogs) but will there be a Word 2010 Viewer and when will it be available?

  • Hi "Word User" - There won't be a new Word 2010 Viewer, and Word 2010 files can be viewed for free in the existing client and new web viewer. - Joanthan Bailor (MS)

  • Why are letters so small?

Comments

Comments: (loading) Collapse