Details: Code-beside Migration



WF Migration Cookbook: WorkflowsStatus: Final Draft, .NET 4 Beta 1Last Modified: DATE \@ "M/d/yyyy h:mm:ss am/pm" 10/22/2009 11:59:03 AMIntroductionIn the .NET Framework 4, Microsoft is releasing the second major version of Windows Workflow Foundation (WF). WF was released in .NET 3.0 (this included the types in the System.Workflow.* namespaces; let’s call this WF3) and enhanced in .NET 3.5. WF3 is also part of the .NET Framework 4, but it exists there alongside new workflow technology (this includes the types in the System.Activities.* namespaces; let’s call this WF4).This paper presents example-oriented step-by-step instructions for redesigning WF3 workflows on WF4. The goal is to cover common scenarios focusing on use of out-of-box and custom ics not covered in this document include custom activity migration, state machines, rules, and workflow services. These are covered in companion documents.The examples and instructions shown in this document use the Visual Studio workflow designer and the C# language.Please see the “WF Migration Overview” document for an introduction to WF3 to WF4 migration, and links to related documents. The latest version of these documents can be found at information contained in this document relates to pre-release software product, which may be substantially modified before its first commercial release. Accordingly, the information may not accurately describe or reflect the software product when first commercially released. This document is provided for informational purposes only, and Microsoft makes no warranties, express or implied, with respect to this document or the information contained in it.Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.?2009 Microsoft Corporation. All rights reserved.Microsoft, Windows, Visual Studio, and the .NET logo are trademarks of the Microsoft group of companies. All other trademarks are property of their respective owners.Workflow ExamplesExample1: Migrating a basic workflowLet’s first look at a basic workflow implemented as a WF3 workflow and then as a WF 4 workflow. The workflow will be configured to delay for 5 seconds and then write “Hello!” to the console.WF3 Basic WorkflowWF3 workflows can be defined either in code or in markup (.xoml file). For this example, the .xoml file looks like this:<SequentialWorkflowActivity x:Class="Cookbook_Workflows_WF3.Workflow1" x:Name="Workflow1" xmlns:x="" xmlns=""><DelayActivity x:Name="Delay_5s" TimeoutDuration="00:00:05" /><CodeActivity x:Name="Code_PrintHello" ExecuteCode="Code_PrintHello_ExecuteCode" /></SequentialWorkflowActivity>Many WF3 workflows require code beside that accompanies the markup, including this example:using System;using System.Workflow.Activities;namespace Cookbook_Workflows_WF3{ public partial class Workflow1 : SequentialWorkflowActivity { private void Code_PrintHello_ExecuteCode(object sender, EventArgs e) { Console.WriteLine("Hello!"); } }}Here is the same workflow implemented on WF4, using the out-of-box WF4 Delay activity and also the out-of-box WriteLine activity in place of the WF3 CodeActivity.WF4 Basic WorkflowHere is the XAML that defines the WF4 workflow:<p:Activity x:Class="Cookbook_Workflows_WF4.Workflow1" xmlns="" xmlns:p="" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x=""> <p:Sequence> <p:Delay DisplayName="Delay_5s">[TimeSpan.FromSeconds(5)]</p:Delay> <p:WriteLine DisplayName="PrintHello">["Hello!"]</p:WriteLine> </p:Sequence></p:Activity>Key differences between the WF3 and WF4 workflows include:The activities used in the WF3 workflow (e.g. DelayActivity) are in the System.Workflow.Activities namespace; in the WF4 workflow, the activities (e.g. Delay) are in the System.Activities.Statements namespace.The WF3 workflow has code beside; the WF4 workflow is entirely XAML.The WF3 workflow uses a CodeActivity to write to the console by executing code in its handler (defined in code beside). The WF4 workflow uses a WriteLine activity. Example 2: Migrating a workflow with databinding and custom activitiesNow we’ll take a look at a more complex workflow that uses activity databinding, a declarative condition, and custom activities.This workflow loads data (a string), checks to see if the length of the data is greater than or equal to 10 and conditionally stores the data. The loading and storing of data is accomplished with custom activities named LoadData and StoreData. Both of these custom activities define a property of type string named ‘Data’ to represent the string being loaded or stored. The code-beside class defines a field of type string to which the activity properties are bound. The conditional logic (this.Data.Length >= 10) is specified as a declarative condition in a .rules file.WF3 Workflow with Declarative Condition and Custom ActivitiesHere is the .xoml file:<SequentialWorkflowActivity x:Class="Cookbook_Workflows_WF3.Workflow2" x:Name="Workflow2" xmlns:ns0="clr-namespace:Cookbook_CustomActivities_WF3;Assembly=WF3Activities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:x="" xmlns=""><ns0:LoadData x:Name="loadData1" Data="{ActivityBind Workflow2,Path=Data}" /><IfElseActivity x:Name="ifElseActivity1"><IfElseBranchActivity x:Name="ifElseBranchActivity1"><IfElseBranchActivity.Condition><RuleConditionReference ConditionName="Condition1" /></IfElseBranchActivity.Condition><ns0:StoreData x:Name="storeData1" Data="{ActivityBind Workflow2,Path=Data}" /></IfElseBranchActivity></IfElseActivity></SequentialWorkflowActivity>Here is the .rules file:<RuleDefinitions xmlns=""> <RuleDefinitions.Conditions> <RuleExpressionCondition Name="Condition1"> <RuleExpressionCondition.Expression> <ns0:CodeBinaryOperatorExpression Operator="GreaterThanOrEqual" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns1:CodeBinaryOperatorExpression.Right xmlns:ns1="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns2:CodePrimitiveExpression xmlns:ns2="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns3:CodePrimitiveExpression.Value xmlns:ns3="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns4:Int32 xmlns:ns4="clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">10</ns4:Int32> </ns3:CodePrimitiveExpression.Value> </ns2:CodePrimitiveExpression> </ns1:CodeBinaryOperatorExpression.Right> <ns5:CodeBinaryOperatorExpression.Left xmlns:ns5="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns6:CodePropertyReferenceExpression PropertyName="Length" xmlns:ns6="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns7:CodePropertyReferenceExpression.TargetObject xmlns:ns7="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns8:CodeFieldReferenceExpression FieldName="Data" xmlns:ns8="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns9:CodeFieldReferenceExpression.TargetObject xmlns:ns9="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns10:CodeThisReferenceExpression xmlns:ns10="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </ns9:CodeFieldReferenceExpression.TargetObject> </ns8:CodeFieldReferenceExpression> </ns7:CodePropertyReferenceExpression.TargetObject> </ns6:CodePropertyReferenceExpression> </ns5:CodeBinaryOperatorExpression.Left> </ns0:CodeBinaryOperatorExpression> </RuleExpressionCondition.Expression> </RuleExpressionCondition> </RuleDefinitions.Conditions></RuleDefinitions>Here is the code-beside .cs file:using System;using System.Workflow.Activities;namespace Cookbook_Workflows_WF3{public partial class Workflow2 : SequentialWorkflowActivity{ public string Data;}}Below is the same workflow in WF4, defined in a single .xaml file.WF4 Workflow with Expression and Interop<p:Activity Name="Workflow2" xmlns="" xmlns:c="clr-namespace:Cookbook_CustomActivities_WF3;assembly=WF3Activities" xmlns:p="" xmlns:sas="clr-namespace:System.Activities.Statements;assembly=System.Workflow.Runtime" xmlns:x=""> <p:Sequence> <p:Sequence.Variables> <p:Variable x:TypeArguments="x:String" Name="data" /> </p:Sequence.Variables> <sas:Interop ActivityType="c:LoadData" DisplayName="loadData1"> <sas:Interop.ActivityProperties> <p:InOutArgument x:TypeArguments="x:String" x:Key="Data">[data]</p:InOutArgument> </sas:Interop.ActivityProperties> </sas:Interop> <p:If Condition="[(data.Length &gt;= 10)]" DisplayName="ifElseActivity1"> <p:If.Then> <p:Sequence DisplayName="ifElseBranchActivity1"> <sas:Interop ActivityType="c:StoreData" DisplayName="storeData1"> <sas:Interop.ActivityProperties> <p:InOutArgument x:TypeArguments="x:String" x:Key="Data">[data]</p:InOutArgument> </sas:Interop.ActivityProperties> </sas:Interop> </p:Sequence> </p:If.Then> </p:If> </p:Sequence></p:Activity>Some key differences between the WF3 and the WF4 workflows:In the WF3 workflow the code-beside defines a field of type string, whereas the WF4 workflow declares a Variable of type string as part of the definition of the Sequence activity.In the WF3 workflow we are using two custom activities. In the WF4 workflow we are using the WF4 Interop activity to execute these custom activities. We could also rewrite the custom activities natively on WF4 and then include them directly (without the Interop layer); see the WF Migration Cookbook for Custom Activities for details.In the WF3 workflow the custom activities’ properties are bound to the code-beside field using activity databinding. In the WF4 workflow, the Interop activity is configured with variable references that serve as bindings for the custom activities’ properties.In the WF3 workflow, the IfElse activity makes use of a named declarative condition (defined in the .rules file) to specify the branching condition. In WF4 workflow, the If activity uses a Visual Basic expression activity.WF3 to WF4 Activity MappingsThe previous section illustrated workflow migration with a couple of examples. This section provides a mapping of WF3 out of box activities to their WF4 counterparts.The following table shows assembly mappings from WF3 to WF4 for activity types.WF3 assemblyWF4 assemblySystem.Workflow.Activities.dllSystem.Activities.dllSystem.ponentModel.dllSystem.Activities.dllSystem.WorkflowServices.dllSystem.ServiceModel.Activities.dllThe following table shows namespace mappings from WF3 to WF4 for activity types.WF3 namespaceWF4 namespaceSystem.Workflow.ActivitiesSystem.Activities.StatementsSystem.ponentModelSystem.ActivitiesSystem.WorkflowServicesSystem.ServiceModel.ActivitiesThe following table shows activity type mappings from WF3 to WF4 for activity types.WF3 ActivityWF4 ActivityCommentsCallExternalMethodActivitySendSee External Data Exchange section belowCancellationHandlerActivityCancellationScopeCodeActivityCodeActivity/NativeActivitySee CodeActivity section below; no code-beside in WF4CompensateActivityCompensateCompensatableSequenceActivityCompensableActivityConditionedActivityGroup-No out of box direct mapping in WF4; typical execution patterns can be modeled by composing other control flow activitiesDelayActivityDelayEventHandlingScopeActivity-No out of box direct mapping in WF4FaultHandlersActivityTryCatchHandleExternalEventActivityReceiveSee External Data Exchange section belowIfElseActivityIfInvokeWebServiceActivitySendThe “Add Service Reference…” feature in Visual Studio creates custom Send activities to call web servicesInvokeWorkflowActivity-No direct mapping in WF4ListenActivityPickParallelActivityParallelPolicyActivity-See WF Migration Guidance: Rules documentReplicatorActivityForEach, ParallelForEachForEach for sequential mode, ParallelForEach for parallel modeSendActivitySendSee WF Migration Guidance: Workflow Services documentReceiveActivityReceiveSee WF Migration Guidance: Workflow Services documentSequenceActivity, SequentialWorkflowActivitySequenceStateMachineWorkflowActivity-No direct mapping. See WF Migration Guidance: State Machine Workflows documentSuspendActivity-No direct mapping in WF4SynchronizationScopeActivity-No direct mapping in WF4TerminateActivity-No direct mapping in WF4ThrowActivityThrowTransactionScopeActivityTransactionScopeCompensatableTransactionScopeActivityTransactionScope + CompensableActivityWebServiceFaultActivity-See WF Migration Guidance: Workflow Services documentWebServiceInputActivity-See WF Migration Guidance: Workflow Services documentWebServiceOutputActivity-See WF Migration Guidance: Workflow Services documentWhileActivityWhileThe WF4 Interop activity provides a migration option for many WF3 custom activities (as shown in the second example). The Interop activity allows WF3 activities to run in a WF3 environment, inline as part of a WF4 workflow.For more information on the Interop activity, please refer to the Interop documentation in the SDK.Details: Code-beside MigrationIn WF3, CodeActivity is an out-of-box activity that adds a handler to the code-beside file where users can execute custom code in a workflow. Additionally, activities in WF3 may also offer events that are handled in code-beside.In WF4, there is no code-beside. The type ‘CodeActivity’ is defined, but is a base class for custom activities. The bottom line is that custom code in WF4 always lives in the Execute method of a custom activity and not in code-beside. WF4 provides expressions support out of the box, as well as several activities that eliminate the need for custom activities in many common cases. Some examples include:WriteLine activityAssign activityVisual Basic expressionsCollection manipulation (AddToCollection, ClearCollection, ExistsInCollection activities, etc.)InvokeMethod activity, for invoking a method on an object or a static method of a typeLet’s look at a simple example where a WF3 CodeActivity is used to calculate and populate the value of a field at runtime, which will then be used by a subsequent part of the workflow (e.g. a Delay activity).WF3: markup and code-besideXAML<CodeActivity x:Name="calculateTimeout1" ExecuteCode="CalculateTimeout_ExecuteCode" />Code-besideTimeSpan delayTimeout;private void CalculateTimeout_ExecuteCode(object sender, EventArgs e){delayTimeout = Utilities.CalculateTimeout();}WF4: custom activitynamespace Cookbook_Workflows_WF4{ using System; using System.Activities; public sealed class CalculateTimeout : CodeActivity<TimeSpan> { protected override void Execute(CodeActivityContext context) { context.SetValue(this.Result, Utilities.CalculateTimeout()); } }}The code-beside field necessary in the WF3 workflow will become a Variable in the resulting WF4 workflow. The WF4 CalculateTimeout activity derives from CodeActivity<TResult> and thus inherits an OutArgument of type TimeSpan, which can be bound to the Variable.An alternative to writing a custom activity is to use an expression as the binding for an InArgument. WF4 expressions allow you to manipulate data in a workflow without having to write custom activities.In the previous example, custom code in the CodeActivity handler was used to calculate a timeout value and set a field that can be bound to by a Delay activity at some later point in the workflow. With expressions, you can directly calculate the timeout value in the Delay activity’s InArgument binding, like so:<Delay>[Utilities.CalculateTimeout()]</Delay>The brackets “[ ]” indicate that the value of the Delay’s Duration property is a Visual Basic expression. This eliminates the need for custom code to call the CalculateTimeout method and store its value somewhere.SummaryIn summary, while the concept of a workflow does not fundamentally change from WF3 to WF4, there are a set of steps required to redesign WF3 workflows as WF4 workflows. Most importantly, WF4 moves away from WF3’s use of code-beside, introduces variables as a way of modeling data in a workflow, and offers expressions as a way of describing the bindings for the Arguments of an activity.Please send us your feedback and questions related to WF migration. We look forward to helping you successfully adopt and utilize WF4 technology.Additional InformationVisual Studio 2010 - WF 4 – .NET Framework 4 - WF 4 Migration Guidance - and WF Samples for .NET Framework - WCF and WF 4 Training Kit - ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download