《WF编程》系列之9 – 编译工作流:使用WFC.EXE

2.3.2 编译工作流

Windows Worfklow提供两种工作流编译方式,通过WorkflowCompiler类(位于System.Workflow.ComponentModel.Compiler名称空间)来编译,或者使用一个命令行编译工具(其实还是通过WorkflowCompiler类实现编译的).

工作流编译器在将工作流定义转换为类型时要遵循一定的步骤.首先是验证工作流定义中的每个活动.我们知道,活动可以定义自己的验证逻辑,举例来说,如果CodeActivity的ExecuteCode事件没有指定的话,它将抛出一个验证失败的错误.验证通过之后.编译器会在一个临时目录中生成源代码(默认语言是C#).最后将生成的源代码编译为一个程序集(就像普通的C#或Visual Basic.NET代码被编译一样).

2.3.2.1 用Wfc.exe编译

WF的命令行编译器叫做wfc.exe.用它来编译工作流,我们需要传递一些参数给它.第一个参数是XOML文件的名称,假设我们的XAML叫做pureXAML.xoml.然后使用-out指令来传递编译后程序集的名称.如果有一些自定义活动是在另外的程序集中定义的,我们需要使用-r指令来引用这些程序集.例如引用一个叫做chapter2_Host.exe的可执行程序集来编译工作流:

wfc.exe purexaml.xoml –r:chapter2_host.exe –out:purexaml.dll

WOW!(不是Vista的广告,也不是某图形处理软件书系的书名,更加不是某网游,仅表示欢呼^O^)

现在我们得到了一个可以在宿主应用程序中使用的程序集.我们可以在宿主应用程序中通过调用Type.GetType并传递assembly-qualified类型名称来动态的加载这个程序集.assembly-qualiied类型名称中包含类型的名称和类型所在的程序集的名称.我们通过x:Class特性指定工作流类型的名称MyWorkflow,在编译的时候又指定了程序集的名称purexaml,所以assembly‑qualiied名称是MyWorkflow,purexaml.下面的代码示范加载程序集并执行工作流:

using (WorkflowRuntime runtime = new WorkflowRuntime())
{
using (AutoResetEvent waitHandle = new AutoResetEvent(false))
{
runtime.WorkflowCompleted += delegate { waitHandle.Set(); };
runtime.WorkflowTerminated += delegate { waitHandle.Set(); };
Type workflowType = Type.GetType("MyWorkflow, purexaml");
WorkflowInstance instance = runtime.CreateWorkflow(workflowType);
instance.Start();
waitHandle.WaitOne();
}
}

前边提到过,工作流是在CLR线程池中的一个线程上异步执行的,所以我们需要等待AutoResetEvent事件的信号来工完成作流.

线程池为异步操作管理后台线程.创建线程是相当”昂贵”的操作,但是通过重复使用线程的方法,线程池可以在应用程序的生命周期内为这笔开销”分期付款”. 当一个操作想要在后台线程上工作时,Runtime从池中分配一个线程给它;当操作完成后,Runtime又将线程还给线程池等待再次分配.

7 Comments

  1. John Rambo 说道:

    这么好的系列必须mark.

  2. sharezone 说道:

    博主,我在开发工作流的时候,创建一个xoml的文件,里面只有一个CodeActivity,我将改事件代码放在了XOML的 <x:code> <!CDATA[] /> </x:code> 中,但是在使用XmlReader加载的时候,就会提示我出错。刚开始接触wf,谢谢。

  3. Windie Chai 说道:

    @sharezone请注意CDATA的写法,应该是 <![CDATA[ ]]>

  4. sharezone 说道:

    谢谢LZ。不过这个地方好像不是根源,我只是在提问题的时候笔误,在实际开发中我是将事件代码放到<![CDATA[…… ]]/>的。提示我工作流验证失败。
    WorkflowInstance instance = workflowRuntime.CreateWorkflow(XmlReader.Create("..\\..\\MyTest.xml"));

  5. Windie Chai 说道:

    @sharezone这绝对是根��。都不符合XML规范了,当然无法验证成功。如果上一次是笔误的话?这一次也是笔误吗?我没法针对你的笔误来解决问题吧。

  6. 毁于随 说道:

    这种编译方法不知道为什么命名空间和Assmbly:XmlnsDefinition的声明并没有编译进去,导致我在测试第13章的时候(我是在另个项目中引用的此章编译生成的dll)时报异常.

Leave a Reply