So – I have to admit – this is pretty much a blatant ripoff of something I saw Dharma do during Don’s first talk that involved workflow on Wed at the PDC, but since I am not sure if he’ll post the code or not – I wanted to put it out there. (just to be clear – this is my attempt to copy what I saw Dharma do – I don’t have access to his code). It fits in pretty well with my chapter on Dynamic Workflow from the book.
UPDATE: Dharma posted his code on his blog – here.
It just shows how really simple it is to create applications that not only host workflow – but that also can dynamically compile workflows (which really brings the potential usage model for workflow up a couple of notches).
Here is my simple XAML/XOML compiler like the one Dharma used. The first argument is the XOML file itself, and any additional assemblies you use (like ones that contain Activities that the workflow uses) are passed in as additional arguments. The AssemblyResolve event handler is necessary because the workflow runtime tries to use the Load context when loading assemblies (which makes total sense).
using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime.Hosting;
using System.Workflow.Runtime;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Threading;
namespace XAMLCompiler
{
class Program
{
static void Main(string[] args)
{
WorkflowCompiler wc = new WorkflowCompiler();
WorkflowCompilerParameters prms = new WorkflowCompilerParameters();
if (args.Length > 1)
{
for (int i = 1; i < args.Length; i++)
prms.ReferencedAssemblies.Add(args[i]);
}
WorkflowCompilerResults wcr = wc.CompileFromFile(prms, args[0]);
if (wcr.Errors.Count > 0)
{
foreach (CompilerError ce in wcr.Errors)
Console.WriteLine(ce.ErrorText);
}
Assembly a = wcr.CompiledAssembly;
if (a != null)
{
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
{
if (rargs.Name == a.FullName)
return a;
else
return null;
};
//extract the workflow
Type t = a.GetTypes()[0];
using (WorkflowRuntime wr = new WorkflowRuntime())
{
wr.StartRuntime();
wr.WorkflowCompleted += delegate { wait.Set(); };
wr.StartWorkflow(t);
wait.WaitOne();
wr.StopRuntime();
}
}
}
static AutoResetEvent wait = new AutoResetEvent(false);
}
}
So if this code is compiled into a console application I can pass the following xaml (ok xoml right now – but I understand they are changing this to xaml to match WPF) as the first argument:
<?Mapping XmlNamespace=”ComponentModel” ClrNamespace=”System.Workflow.ComponentModel” Assembly=”System.Workflow.ComponentModel” ?>
<?Mapping XmlNamespace=”Compiler” ClrNamespace=”System.Workflow.ComponentModel.Compiler” Assembly=”System.Workflow.ComponentModel” ?>
<?Mapping XmlNamespace=”Activities” ClrNamespace=”System.Workflow.Activities” Assembly=”System.Workflow.Activities” ?>
<?Mapping XmlNamespace=”RuleConditions” ClrNamespace=”System.Workflow.Activities.Rules” Assembly=”System.Workflow.Activities.Rules” ?>
<?Mapping XmlNamespace=”MyActivities” ClrNamespace=”MyActivities” Assembly=”myactivity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null” ?>
<SequentialWorkflow x:Class=”MyWorkflow” ID=”MyWorkflow” xmlns:x=”Definition” xmlns=”Activities”>
<ns0:MyActivity ID=”myActivity1″ xmlns:ns0=”MyActivities” />
</SequentialWorkflow>
The second argument would be the name of the assembly that contains the MyActivities.MyActivity type – which you can see here
using System;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.ComponentModel;
namespace MyActivities
{
[ToolboxItem(typeof(ActivityToolboxItem))]
public class MyActivity : Activity
{
protected override Status Execute(ActivityExecutionContext ctx)
{
Console.WriteLine(“HEllo from My Activity”);
return Status.Closed;
}
}
}
This assembly can be compiled on the command line like this:
csc /t:library /r:”C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215\Windows Workflow Foundation\System.Workflow.ComponentModel.dll” myactivity.cs
You can download the full source here –
XAMLCompiler.zip (22.4 KB)