Workflow:实现一个简单的审批流程
1. 创建一个空白的项目,在其中创建Host – Windows Console Application,Client – Windows forms Application和DataExchangeWorkflows – Activity Library这三个项目。创建后应该结构类似于下图:
2. 将工作流DataExchangeActivity.xaml设计为如下样式:
有几点需要注意:
1) 第一个Receive Activity的CanCreateInstance必须为True,否则客户端调用此Receive无法生成实例(一个工作流只需要第一个的CanCreateInstance为True)
2) TicketId变量保存生成的工作流示例编号,在后面更新时客户端将根据TicketId来更新状态。
3) _handler的类型是CorrelationHandle。_handler的作用是根据客户端发送过来的TicketId,搜索相匹配的工作流的TicketId。
4) 刚才说过,_handler是用于搜索相匹配的工作流的TicketId,在第二个Receive Activity「CheckCredit」的ServiceContractName不能为空白,否则在设置CorrelationOn的属性的时候,选择Id属性会报”ServiceContractName and OperationName properties of activity ‘Receive’ must be set in order to generate XPath”这个错。
5) 需要设置三个Arguments,用于传递Receive Activity「CheckCredit」的参数。
6) 最后生成的XML如下:
1 <Activity mc:Ignorable="sap sap2010 sads" x:Class="DataExchangeWorkflows.DataExchangeActivity" 2 3 xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" 4 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 7 xmlns:mca="clr-namespace:Microsoft.CSharp.Activities;assembly=System.Activities" 8 9 xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" 10 11 xmlns:sads="http://schemas.microsoft.com/netfx/2010/xaml/activities/debugger" 12 13 xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" 14 15 xmlns:sap2010="http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation" 16 17 xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" 18 19 xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib" 20 21 xmlns:ssx="clr-namespace:System.ServiceModel.XamlIntegration;assembly=System.ServiceModel" 22 23 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 24 25 <x:Members> 26 27 <x:Property Name="action" Type="InArgument(x:String)" /> 28 29 <x:Property Name="reviewId" Type="InArgument(x:Int32)" /> 30 31 <x:Property Name="comment" Type="InArgument(x:String)" /> 32 33 </x:Members> 34 35 <sap2010:ExpressionActivityEditor.ExpressionActivityEditor>C#</sap2010:ExpressionActivityEditor.ExpressionActivityEditor> 36 37 <sap2010:WorkflowViewState.IdRef>DataExchangeWorkflows.DataExchangeActivity_1</sap2010:WorkflowViewState.IdRef> 38 39 <TextExpression.NamespacesForImplementation> 40 41 <sco:Collection x:TypeArguments="x:String"> 42 43 <x:String>System</x:String> 44 45 <x:String>System.Collections.Generic</x:String> 46 47 <x:String>System.Data</x:String> 48 49 <x:String>System.Linq</x:String> 50 51 <x:String>System.Text</x:String> 52 53 <x:String>System.ServiceModel.Activities</x:String> 54 55 </sco:Collection> 56 57 </TextExpression.NamespacesForImplementation> 58 59 <TextExpression.ReferencesForImplementation> 60 61 <sco:Collection x:TypeArguments="AssemblyReference"> 62 63 <AssemblyReference>Microsoft.CSharp</AssemblyReference> 64 65 <AssemblyReference>System</AssemblyReference> 66 67 <AssemblyReference>System.Activities</AssemblyReference> 68 69 <AssemblyReference>System.Core</AssemblyReference> 70 71 <AssemblyReference>System.Data</AssemblyReference> 72 73 <AssemblyReference>System.Runtime.Serialization</AssemblyReference> 74 75 <AssemblyReference>System.ServiceModel</AssemblyReference> 76 77 <AssemblyReference>System.ServiceModel.Activities</AssemblyReference> 78 79 <AssemblyReference>System.Xaml</AssemblyReference> 80 81 <AssemblyReference>System.Xml</AssemblyReference> 82 83 <AssemblyReference>System.Xml.Linq</AssemblyReference> 84 85 <AssemblyReference>mscorlib</AssemblyReference> 86 87 <AssemblyReference>DataExchangeWorkflows</AssemblyReference> 88 89 </sco:Collection> 90 91 </TextExpression.ReferencesForImplementation> 92 93 <Sequence sap2010:WorkflowViewState.IdRef="Sequence_1"> 94 95 <Sequence.Variables> 96 97 <Variable x:TypeArguments="p:CorrelationHandle" Name="_handler" /> 98 99 <Variable x:TypeArguments="x:Int32" Default="-1" Name="TicketId" /> 100 101 </Sequence.Variables> 102 103 <Pick sap2010:WorkflowViewState.IdRef="Pick_1"> 104 105 <PickBranch DisplayName="Branch1" sap2010:WorkflowViewState.IdRef="PickBranch_1"> 106 107 <PickBranch.Trigger> 108 109 <p:Receive CanCreateInstance="True" sap2010:WorkflowViewState.IdRef="Receive_2" OperationName="ReceiveOrder" /> 110 111 </PickBranch.Trigger> 112 113 <Sequence sap2010:WorkflowViewState.IdRef="Sequence_2"> 114 115 <Assign sap2010:WorkflowViewState.IdRef="Assign_1"> 116 117 <Assign.To> 118 119 <OutArgument x:TypeArguments="x:Int32"> 120 121 <mca:CSharpReference x:TypeArguments="x:Int32">TicketId</mca:CSharpReference> 122 123 </OutArgument> 124 125 </Assign.To> 126 127 <Assign.Value> 128 129 <InArgument x:TypeArguments="x:Int32"> 130 131 <mca:CSharpValue x:TypeArguments="x:Int32">new Random().Next()</mca:CSharpValue> 132 133 </InArgument> 134 135 </Assign.Value> 136 137 </Assign> 138 139 <p:InitializeCorrelation sap2010:WorkflowViewState.IdRef="InitializeCorrelation_1"> 140 141 <p:InitializeCorrelation.Correlation> 142 143 <InArgument x:TypeArguments="p:CorrelationHandle"> 144 145 <mca:CSharpValue x:TypeArguments="p:CorrelationHandle">_handler</mca:CSharpValue> 146 147 </InArgument> 148 149 </p:InitializeCorrelation.Correlation> 150 151 <InArgument x:TypeArguments="x:String" x:Key="Id"> 152 153 <mca:CSharpValue x:TypeArguments="x:String">TicketId.ToString()</mca:CSharpValue> 154 155 </InArgument> 156 157 </p:InitializeCorrelation> 158 159 <WriteLine sap2010:WorkflowViewState.IdRef="WriteLine_1"> 160 161 <InArgument x:TypeArguments="x:String"> 162 163 <mca:CSharpValue x:TypeArguments="x:String">"流程被创建,编号为:" + TicketId.ToString()</mca:CSharpValue> 164 165 </InArgument> 166 167 </WriteLine> 168 169 </Sequence> 170 171 </PickBranch> 172 173 </Pick> 174 175 <Pick sap2010:WorkflowViewState.IdRef="Pick_2"> 176 177 <PickBranch DisplayName="Branch1" sap2010:WorkflowViewState.IdRef="PickBranch_2"> 178 179 <PickBranch.Trigger> 180 181 <p:Receive sap2010:WorkflowViewState.IdRef="Receive_3" OperationName="CheckCredit" ServiceContractName="ICheckCredit"> 182 183 <p:Receive.CorrelatesOn> 184 185 <p:XPathMessageQuery x:Key="Id"> 186 187 <p:XPathMessageQuery.Namespaces> 188 189 <ssx:XPathMessageContextMarkup> 190 191 <x:String x:Key="xgSc">http://tempuri.org/</x:String> 192 193 </ssx:XPathMessageContextMarkup> 194 195 </p:XPathMessageQuery.Namespaces>sm:body()/xgSc:CheckCredit/xgSc:id</p:XPathMessageQuery> 196 197 </p:Receive.CorrelatesOn> 198 199 <p:Receive.CorrelatesWith> 200 201 <InArgument x:TypeArguments="p:CorrelationHandle"> 202 203 <mca:CSharpValue x:TypeArguments="p:CorrelationHandle">_handler</mca:CSharpValue> 204 205 </InArgument> 206 207 </p:Receive.CorrelatesWith> 208 209 <p:ReceiveParametersContent> 210 211 <OutArgument x:TypeArguments="x:String" x:Key="action"> 212 213 <mca:CSharpReference x:TypeArguments="x:String">action</mca:CSharpReference> 214 215 </OutArgument> 216 217 <OutArgument x:TypeArguments="x:String" x:Key="comment"> 218 219 <mca:CSharpReference x:TypeArguments="x:String">comment</mca:CSharpReference> 220 221 </OutArgument> 222 223 <OutArgument x:TypeArguments="x:Int32" x:Key="id"> 224 225 <mca:CSharpReference x:TypeArguments="x:Int32">reviewId</mca:CSharpReference> 226 227 </OutArgument> 228 229 </p:ReceiveParametersContent> 230 231 </p:Receive> 232 233 </PickBranch.Trigger> 234 235 <If sap2010:WorkflowViewState.IdRef="If_1"> 236 237 <If.Condition> 238 239 <InArgument x:TypeArguments="x:Boolean"> 240 241 <mca:CSharpValue x:TypeArguments="x:Boolean">action.ToUpper() == "APPROVAL"</mca:CSharpValue> 242 243 </InArgument> 244 245 </If.Condition> 246 247 <If.Then> 248 249 <WriteLine sap2010:WorkflowViewState.IdRef="WriteLine_2"> 250 251 <InArgument x:TypeArguments="x:String"> 252 253 <mca:CSharpValue x:TypeArguments="x:String">"流程" + TicketId.ToString() + "通过审核"</mca:CSharpValue> 254 255 </InArgument> 256 257 </WriteLine> 258 259 </If.Then> 260 261 <If.Else> 262 263 <WriteLine sap2010:WorkflowViewState.IdRef="WriteLine_3"> 264 265 <InArgument x:TypeArguments="x:String"> 266 267 <mca:CSharpValue x:TypeArguments="x:String">"流程" + TicketId.ToString() + "被驳回"</mca:CSharpValue> 268 269 </InArgument> 270 271 </WriteLine> 272 273 </If.Else> 274 275 </If> 276 277 </PickBranch> 278 279 </Pick> 280 281 <sads:DebugSymbol.Symbol>d2BFOlxLZXZpbl9Eb2N1bWVudFx3b3Jrc3BhY2VcRGF0YUV4Y2hhbmdlU29sdXRpb25cRGF0YUV4Y2hhbmdlV29ya2Zsb3dzXERhdGFFeGNoYW5nZUFjdGl2aXR5LnhhbWwbLwOOAQ4CAQEyMzI3AgECNAVXDAIBM1gFjAEMAgEDNQdWFAIBNFkHiwEUAgEENws3egIBVzkJVRQCATVbC3QXAgEadgmKAQ4CAQU6C0UUAgFKRgtPJQIBPVALVBcCATZmEWZiAgEtaxFrXQIBJ3ERcV4CASFuEW5eAgEbeQ95bAIBBn0NgQEZAgEThAENiAEZAgEMQhFCYQIBUT0RPV4CAUtND01gAgFESRFJYgIBPlIPUm8CATd/EX9yAgEUhgERhgFxAgEN</sads:DebugSymbol.Symbol> 282 283 </Sequence> 284 285 <sap2010:WorkflowViewState.ViewStateManager> 286 287 <sap2010:ViewStateManager> 288 289 <sap2010:ViewStateData Id="Receive_2" sap:VirtualizedContainerService.HintSize="255,90" /> 290 291 <sap2010:ViewStateData Id="Assign_1" sap:VirtualizedContainerService.HintSize="242,62" /> 292 293 <sap2010:ViewStateData Id="InitializeCorrelation_1" sap:VirtualizedContainerService.HintSize="242,97" /> 294 295 <sap2010:ViewStateData Id="WriteLine_1" sap:VirtualizedContainerService.HintSize="242,62" /> 296 297 <sap2010:ViewStateData Id="Sequence_2" sap:VirtualizedContainerService.HintSize="264,425"> 298 299 <sap:WorkflowViewStateService.ViewState> 300 301 <scg:Dictionary x:TypeArguments="x:String, x:Object"> 302 303 <x:Boolean x:Key="IsExpanded">True</x:Boolean> 304 305 </scg:Dictionary> 306 307 </sap:WorkflowViewStateService.ViewState> 308 309 </sap2010:ViewStateData> 310 311 <sap2010:ViewStateData Id="PickBranch_1" sap:VirtualizedContainerService.HintSize="294,713" /> 312 313 <sap2010:ViewStateData Id="Pick_1" sap:VirtualizedContainerService.HintSize="608,759" /> 314 315 <sap2010:ViewStateData Id="Receive_3" sap:VirtualizedContainerService.HintSize="255,90" /> 316 317 <sap2010:ViewStateData Id="WriteLine_2" sap:VirtualizedContainerService.HintSize="211,62" /> 318 319 <sap2010:ViewStateData Id="WriteLine_3" sap:VirtualizedContainerService.HintSize="211,62" /> 320 321 <sap2010:ViewStateData Id="If_1" sap:VirtualizedContainerService.HintSize="464,212" /> 322 323 <sap2010:ViewStateData Id="PickBranch_2" sap:VirtualizedContainerService.HintSize="494,500" /> 324 325 <sap2010:ViewStateData Id="Pick_2" sap:VirtualizedContainerService.HintSize="608,546" /> 326 327 <sap2010:ViewStateData Id="Sequence_1" sap:VirtualizedContainerService.HintSize="630,1469"> 328 329 <sap:WorkflowViewStateService.ViewState> 330 331 <scg:Dictionary x:TypeArguments="x:String, x:Object"> 332 333 <x:Boolean x:Key="IsExpanded">True</x:Boolean> 334 335 </scg:Dictionary> 336 337 </sap:WorkflowViewStateService.ViewState> 338 339 </sap2010:ViewStateData> 340 341 <sap2010:ViewStateData Id="DataExchangeWorkflows.DataExchangeActivity_1" sap:VirtualizedContainerService.HintSize="670,1549" /> 342 343 </sap2010:ViewStateManager> 344 345 </sap2010:WorkflowViewState.ViewStateManager> 346 347 </Activity>
3. Host项目引入System.Activities, System.ServiceModel.Activities和System.ServiceModel。如下图所示:
4. 修改Host项目的program.cs如下:
1 static void Main(string[] args) 2 3 { 4 5 var host = new WorkflowServiceHost( 6 7 new DataExchangeActivity(), 8 9 new Uri("http://localhost:8080/WS")); 10 11 12 13 host.AddDefaultEndpoints(); 14 15 host.Description.Behaviors.Add( 16 17 new ServiceMetadataBehavior() { HttpGetEnabled = true }); 18 19 20 21 host.AddServiceEndpoint( 22 23 "IMetadataExchange", 24 25 MetadataExchangeBindings.CreateMexHttpBinding(), 26 27 "mex"); 28 29 30 31 host.Open(); 32 33 Console.WriteLine("Server is ready."); 34 35 Console.Read(); 36 37 }
5. 编译Host,然后以Administrator身份运行host.exe,这时会启动WCF,终端窗口显示如下:
6. 这时打开浏览器,浏览http://localhost:8080/ws,会显示如下页面:
7. 打开VS Command Prompt(VS命令行终端),运行svcutil.exe http://localhost:8080/ws?wsdl。结果如下图。这时会生成两个文件,DataExchangeActivity.cs和output.config。将这两个文件copy到client项目中,output.config改名为app.config。
8. 修改Client的Form1,界面如下:
9. 代码如下(很简单就不解释了):
1 private void button1_Click(object sender, EventArgs e) 2 3 { 4 5 var proxy = new DataExchangeActivityClient(); 6 7 proxy.ReceiveOrder(); 8 9 } 10 11 12 13 private void button2_Click(object sender, EventArgs e) 14 15 { 16 17 var proxy = new CheckCreditClient(); 18 19 proxy.CheckCredit(textAction.Text.Trim(), "", int.Parse(textId.Text)); 20 21 }
10. 运行Client后,启动流程并且输入对应工作流的审批意见后,结果如下: