How to Author, Publish, and Manage a Workflow for Workflow Manager 1.0

 

Updated: September 28, 2012

Authoring, publishing, and managing workflows uses the Workflow Manager API. This topic describes how to use the methods and classes of the Workflow Manager Client API to work with workflows.

Authoring Workflows

Authoring workflows in Workflow Manager 1.0 is similar to authoring in any workflow environment. Workflows are created declaratively using XAML that defines a hierarchy of predefined activities. The following code example (from the Custom Activities sample) is a declarative workflow created to run in Workflow Manager 1.0.

<Activity mc:Ignorable="sap sap2010 sads" x:Class="MoviesActivityLibrary.GetMovies"  
 xmlns="https://schemas.microsoft.com/netfx/2009/xaml/activities"  
 xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"  
 xmlns:mca="clr-namespace:Microsoft.CSharp.Activities;assembly=System.Activities"  
 xmlns:p="https://schemas.microsoft.com/workflow/2012/07/xaml/activities"  
 xmlns:sads="https://schemas.microsoft.com/netfx/2010/xaml/activities/debugger"  
 xmlns:sap="https://schemas.microsoft.com/netfx/2009/xaml/activities/presentation"  
 xmlns:sap2010="https://schemas.microsoft.com/netfx/2010/xaml/activities/presentation"  
 xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib"  
 xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib"  
 xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">  
  <x:Members>  
    <x:Property Name="searchKeyword" Type="InArgument(x:String)" />  
    <x:Property Name="numItems" Type="InArgument(x:Int32)" />  
    <x:Property Name="videoDV" Type="OutArgument(p:DynamicValue)" />  
  </x:Members>  
  <sap2010:ExpressionActivityEditor.ExpressionActivityEditor>C#</sap2010:ExpressionActivityEditor.ExpressionActivityEditor>  
  <sap2010:WorkflowViewState.IdRef>ActivityLibrary2.Activity1_1</sap2010:WorkflowViewState.IdRef>  
  <TextExpression.NamespacesForImplementation>  
    <sco:Collection x:TypeArguments="x:String">  
      <x:String>System</x:String>  
      <x:String>System.Collections.Generic</x:String>  
      <x:String>System.Data</x:String>  
      <x:String>System.Linq</x:String>  
      <x:String>System.Text</x:String>  
      <x:String>Microsoft.Activities</x:String>  
    </sco:Collection>  
  </TextExpression.NamespacesForImplementation>  
  <TextExpression.ReferencesForImplementation>  
    <sco:Collection x:TypeArguments="AssemblyReference">  
      <AssemblyReference>Microsoft.Activities</AssemblyReference>  
      <AssemblyReference>Microsoft.CSharp</AssemblyReference>  
      <AssemblyReference>Microsoft.Workflow.Common</AssemblyReference>  
      <AssemblyReference>Microsoft.Workflow.Tracing</AssemblyReference>  
      <AssemblyReference>System</AssemblyReference>  
      <AssemblyReference>System.Activities</AssemblyReference>  
      <AssemblyReference>System.Core</AssemblyReference>  
      <AssemblyReference>System.Data</AssemblyReference>  
      <AssemblyReference>System.Runtime.Serialization</AssemblyReference>  
      <AssemblyReference>System.ServiceModel</AssemblyReference>  
      <AssemblyReference>System.ServiceModel.Activities</AssemblyReference>  
      <AssemblyReference>System.Xaml</AssemblyReference>  
      <AssemblyReference>System.Xml</AssemblyReference>  
      <AssemblyReference>System.Xml.Linq</AssemblyReference>  
      <AssemblyReference>mscorlib</AssemblyReference>  
      <AssemblyReference>MoviesActivityLibrary</AssemblyReference>  
    </sco:Collection>  
  </TextExpression.ReferencesForImplementation>  
  <Sequence DisplayName="GetMovies" sap2010:WorkflowViewState.IdRef="Sequence_1">  
    <p:HttpGet DisplayName="HttpGetFromNetflix" sap2010:WorkflowViewState.IdRef="HttpGet_1" RetryOnConnectionFailure="True">  
      <p:HttpGet.ResponseContent>  
        <OutArgument x:TypeArguments="p:DynamicValue">  
          <mca:CSharpReference x:TypeArguments="p:DynamicValue">videoDV</mca:CSharpReference>  
        </OutArgument>  
      </p:HttpGet.ResponseContent>  
      <p:HttpGet.Uri>  
        <InArgument x:TypeArguments="x:String">  
          <mca:CSharpValue x:TypeArguments="x:String">"http://odata.netflix.com/Catalog/Titles?$filter=substringof('" + searchKeyword + "', Name)&$format=json&$top=" + numItems + "&$select=Name, Synopsis"</mca:CSharpValue>  
        </InArgument>  
      </p:HttpGet.Uri>  
    </p:HttpGet>  
    <sads:DebugSymbol.Symbol>d3dcXHNjcmF0Y2gyXHNjcmF0Y2hcZ2dvZ29sb1xCMiAtIFRlc3RcQ3VzdG9tQ29kZUFjdGl2aXRpZXNcQ3VzdG9tQ29kZUFjdGl2aXR5U2FtcGxlXE1vdmllc0FjdGl2aXR5TGlicmFyeVxHZXRNb3ZpZXMueGFtbAQxAz8OAgEBMgU9EQIBAjoLOusBAgEHNQs1XgIBAw==</sads:DebugSymbol.Symbol>  
  </Sequence>  
  <sap2010:WorkflowViewState.ViewStateManager>  
    <sap2010:ViewStateManager>  
      <sap2010:ViewStateData Id="HttpGet_1" sap:VirtualizedContainerService.HintSize="284,120" />  
      <sap2010:ViewStateData Id="Sequence_1" sap:VirtualizedContainerService.HintSize="306,244">  
        <sap:WorkflowViewStateService.ViewState>  
          <scg:Dictionary x:TypeArguments="x:String, x:Object">  
            <x:Boolean x:Key="IsExpanded">True</x:Boolean>  
          </scg:Dictionary>  
        </sap:WorkflowViewStateService.ViewState>  
      </sap2010:ViewStateData>  
      <sap2010:ViewStateData Id="ActivityLibrary2.Activity1_1" sap:VirtualizedContainerService.HintSize="346,324" />  
    </sap2010:ViewStateManager>  
  </sap2010:WorkflowViewState.ViewStateManager>  
</Activity>  

The following screenshot shows the workflow opened in Visual Studio 2012.

GetMovies Workflow

The workflow in this example retrieves movie information from a public web service based on search parameters. These parameters are defined as properties (a search keyword and a record count). The workflow then returns the retrieved information as a DynamicValue, letting the caller handle the returned data as a property bag.

Publishing Workflows

Workflows hosted using Workflow Manager must first be published to a scope. Interacting with a scope is done using the WorkflowManagementClient. The following code sample demonstrates how to create a workflow scope for the purposes of this sample.

var rootClient = new WorkflowManagementClient(new Uri(rootScope));  
  
            return rootClient.CurrentScope.PublishChildScope(scopeName,  
                new ScopeDescription()  
                {  
                    UserComments = string.Format("For {0} sample only", scopeName)  
                });  

Once the scope has been established, the workflow can be published to the scope. All XAML documents are uploaded as Activities using an ActivityDescription. Workflows are then given associated metadata via a WorkflowDescription. The following code sample demonstrates how to publish the workflow and its corresponding activity.

// publish the activity description related with the workflow  
client.Activities.Publish(  
new ActivityDescription(WorkflowUtils.Translate(xamlFilePath)) { Name = workflowName });  
  
// now, publish the workflow description  
WorkflowDescription description = new WorkflowDescription  
{  
Name = workflowName,  
ActivityPath = workflowName,  
// additional properties elided for simplicity  
};  
  
// publish!  
client.Workflows.Publish(description);  

Managing workflows

Once workflows are published to Workflow Manager, they are executed and their status can be retrieved. The following code example demonstrates how to execute a published workflow. Starting a workflow uses a T:Microsoft.Workflow.Client.WorkflowStartInfo object to store start information, similar to the way a process uses a StartInfo object.

Console.Write("Starting workflow instance...");  
WorkflowStartParameters startParameters = new WorkflowStartParameters();  
startParameters.Content.Add("Title", "Titanic");  
startParameters.Content.Add("NumberOfMovies", 3);  
string instanceId = client.Workflows.Start(workflowName, startParameters);  

The following code example demonstrates how to query the status of a running workflow. The status is returned as a string.

WorkflowInstanceInfo instanceInfo = client.Instances.Get(workflowName, instanceId);  
currentStatus = instanceInfo.UserStatus;  
  
if (instanceInfo.WorkflowStatus == WorkflowInstanceStatus.Completed)  
{  
    Console.WriteLine("\nWorkflow instance completed");  
}