Harry Pierson was in my WF/WCF course I taught a few weeks ago. He posted on his blog about features he thought were cool in WF here.
One of the ones that I thought was interesting that he caught during my course was
that the WorkflowLoaderService is actually a pluggable service (just like every other
service except for the WorkflowQueueingService). So of course it came
to my mind to show an example of why you might want to create a custom loader service.
The WorkflowLoaderService is a very simple API – it has two methods name CreateInstance
both which return an instance of Activity. Everytime a Host calls WorkflowRuntime.CreateWorkflow
– the WorkflowLoaderService is called to actually create the instance. One of
the CreateInstance methods is for compiled Activities (the one that takes as its argument
a Type) and one for XAML activation (the one that takes as its arguments two XmlReaders
– one for the workflow and one for rules).
The DefaultWorkflowLoaderService is fairly simple – the CreateInstance that takes
a Type uses Activator.CreateInstance to create an instance of the Activity Type.
The one that takes XAML is slightly more complex – but essentially uses the WorkflowMarkupSerializer
to turn the XAML into an Activity.
So why might you want to replace this service? Well – there are many scenarios
– but one that always comes to mind for me resolves around rule loading.
One of the great features of WF is to be able to model some of you logic in rules
versus code. In Visual Studio – whenever you add rules, those rules are stored
in a .rules file along side your workflow files. These .rules files are then
compiled into the assembly as resources. Whenever an Activity first needs a
rule, there is an infrastructure that loads the .rules file into a RuleDefinitions
type (containing both any RuleSets and RuleConditions) – and stuff the object into
a well-known DependencyProperty in the root Activity.
One of the features of rules that is so useful is being able to replace them at runtime
with a different set of rules – but with the DefaultWorkflowLoaderService – the only
way you can do that is if you use XAML activation. But what if you want to replace
rules on a compiled Activity type without having to recompile it. The default
infrastructure doesn’t allow this.
But – if you build your own WorkflowLoaderService – when a compiled Activity type
is requested – you could read the rules from an alternate location (based on configuration
or some other algorithm) and then dynamically create the RuleDefinitions and stick
it into the Activity using the well-known DependencyProperty. Here is the code
that does this in a simulated way (note that you’d have to change the algorithm that
loads the alternate rules to something useful):
public class DynamicRuleWorkflowLoader
: DefaultWorkflowLoaderService
{
protected override System.Workflow.ComponentModel.Activity
CreateInstance(Type workflowType)
{
Activity a = base.CreateInstance(workflowType);
WorkflowMarkupSerializer s = new WorkflowMarkupSerializer();
object o = s.Deserialize(XmlReader.Create(“AlternateRules.xml”));
a.SetValue(RuleDefinitions.RuleDefinitionsProperty, o);
return a;
}
protected override Activity
CreateInstance(System.Xml.XmlReader workflowDefinitionReader, System.Xml.XmlReader
rulesReader)
{
return base.CreateInstance(workflowDefinitionReader,
rulesReader);
}
}