Workflow compilation is just as important as workflow development because it enables you to execute workflows. A couple of methods of workflow compilation that are discussed next. In addition to the two methods outlined here, when you’re developing in Visual Studio, you can compile workflows from within the tool, as with any other type of .NET application built in Visual Studio.
The Windows Workflow Foundation SDK includes a command-line utility, wfc.exe, for manually compiling workflow files into executable assemblies. As discussed earlier in this chapter, this utility takes a workflow definition and compiles it into a .NET assembly for distribution and execution. You can use any type of workflow development model with the wfc.exe compiler. The following examples use different development types.
The first example uses the markup-only mode and outputs the XAML to an assembly called MyAssembly.dll:
wfc.exe /out:MyAssembly.dll /target:assembly MyWorkflow.xoml
The command-line compiler also shows errors in compilation just as though you were compiling inside Visual Studio. The following example shows an attempt to compile a workflow developed in the code-only mode. However, because there are a couple Code activities inside the workflow, and their corresponding ExecuteCode event handlers are not wired, wfc.exe cannot compile, and a message is displayed. Also, note that the code and markup development mode are supported by providing both .xoml and .cs files as parameters.
wfc.exe /out:MyAssembly.dll /target:assembly MyWorkflow.cs MyWorkflow.designer.cs Microsoft (R) Windows Workflow Compiler version 3.0.0.0 Copyright (C) Microsoft Corporation 2005. All rights reserved. The compiler generated the following messages(s): MyWorkflow.cs : error 278: Activity 'codeActivity1' validation failed: Property 'ExecuteCode' is not set. MyWorkflow.cs : error 278: Activity 'codeActivity2' validation failed: Property 'ExecuteCode' is not set. Compilation finished with 0 warning(s), 2 error(s).
There are also a few other options for the wfc.exe utility, such as whether to create the debugging information for the assembly and strong name information. If you type wfc.exe /? on the command line, you are presented with a full list of the utility’s options, as follows:
Windows Workflow Compiler Options wfc.exe <XAML file list> /target:assembly [<vb/cs file list>] [/language:...] [/out:...] [/reference:...] [/library:...] [/debug...] [/nocode...] [/checktypes...] - OUTPUT FILE - /out:<file> Output file name /target:assembly Build a Windows Workflow assembly (default). Short form: /t:assembly /target:exe Build a Windows Workflow application. Short form: /t:exe /delaysign[+|-] Delay-sign the assembly using only the public portion of the strong name key. /keyfile:<file> Specifies a strong name key file. /keycontainer:<string> Specifies a strong name key container. - INPUT FILES - <XAML file list> XAML source file name(s). <vb/cs file list> Codebeside file name(s). /reference:<file list> Reference metadata from the specified assembly file(s). Short form is '/r:'. /library:<path list> Set of directories where to lookup for the references. Short form is '/lib:'. - CODE GENERATION - /debug[+|-] Emit full debugging information. The default is '+'. /nocode[+|-] Disallow code-beside and code-within models. The default is '-'. Short form is '/nc:'. /checktypes[+|-] Check for permitted types in wfc.exe.config file. The default is '-'. Short form is '/ct:'. - LANGUAGE - /language:[cs|vb] The language to use for the generated class. The default is 'CS' (C#). Short form is '/l:'. /rootnamespace:<string> Specifies the root Namespace for all type declarations. Valid only for 'VB' (Visual Basic) language. Short form is '/rns:'. - MISCELLANEOUS - /help Display this usage message. Short form is '/?'. /nologo Suppress compiler copyright message. Short form is '/n'. /nowarn Ignore compiler warnings. Short form is '/w'.
You can also compile workflows in .NET code with the WorkflowCompiler class. This comes in handy in scenarios where end users are developing and modifying workflows in custom applications. In the following example, a WorkflowCompiler instance compiles a file called XomlWorkflow.xoml. In addition, the WorkflowCompilerParameters class is used to tell the compiler to reference MyAssembly.dll, output the workflow to MyWorkflow.dll, and tell the compiler not to generate debugging information. After the workflow is compiled, there is a check to make sure that no errors occurred. If that is the case, the compiler output is printed to the console, and the types in the newly generated .NET assembly are printed as well. If errors did occur during compilation, they are shown to the user.
WorkflowCompiler compiler = new WorkflowCompiler(); WorkflowCompilerParameters parms = new WorkflowCompilerParameters(new string[] { @"C:\MyAssembly.dll" }, "MyWorkflow.dll", false); WorkflowCompilerResults res = compiler.Compile(parms, @"C:\XomlWorkflow.xoml"); if (res.Errors.Count == 0) { if (res.Output.Count > 0) { // print the compiler output Console.WriteLine("Compiler output:"); foreach (string msg in res.Output) { Console.WriteLine(msg); } } // print the types in the assembly Console.WriteLine("Types in the assembly:"); Type[] types = res.CompiledAssembly.GetTypes(); foreach (Type type in types) { Console.WriteLine(type.FullName); } } else { foreach (CompilerError err in res.Errors) { Console.WriteLine("Error: " + err.ErrorText); } }
Because the WorkflowCompilerResults class exposes the CompiledAssembly property, the developer is instantly given access to run the newly compiled workflow. The following is an example of this scenario:
WorkflowRuntime runtime = new WorkflowRuntime(); WorkflowInstance instance = runtime.CreateWorkflow(typeof(res.CompiledAssembly.GetTypes()[0])); instance.Start();
No matter which compilation method you use - the command-line compiler, the WorkflowCompiler class, or Visual Studio - the following steps occur to ensure a successful compilation:
Validation is performed on workflow activities. If errors occur here, compilation stops.
A partial class is generated, which is fed to the workflow compiler.
Code is generated to wire event handlers and set properties (as described earlier regarding the output from Lutz’s Reflector).
The partial class generated in step 2 is fed with any partial code classes written by the developer to the workflow compiler, and a .NET assembly is generated.