We have created a Win Form app that programmatically builds a workflow. It contains one sequential workflow object, and has activities implemented in a separate DLL. The generated workflow definition is then serialized out to a xaml file. We then compile the xaml definition to an assembly, and executes the workflow using dharmas compiler sample. The workflow library is a class library wrapper for the runtime, and both the workflow library and activitiy library dlls are strong named and placed in the GAC.
The dynamic compilation and execution all works fine until we try and pass parameters from the workflow to the activity (an applicationID, for example).
To test, my custom activity simply writes out the workflow instanceID and the passed in AppID from the workflow to a new element in an xml file, which is read via an event and displayed in a listview on the Win Form (had interesting cross-threading issue solved by calling InvokeRequired on the listview - the finished app will have no UI, so this wont be a problem).
If I compile the workflow dll and execute it using a console app, it works fine; I can see the new wf instance appear in my xml file, along with the passed in parameter, so I should have set up my activityBindings correctly in code.
However, when i serialise out the instance to see the xaml that is created with the params and try to incorporate that in my own xaml to compile dynamically, the IDE throws a compiler error when i try to start the wf.
This is the code generated when i serialize out the xaml:
< 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="myDemoWFLibrary" ClrNamespace="myDemoWFLibrary" Assembly="myDemoWFLibrary, Version=3.0.0.0, Culture=neutral, PublicKeyToken=e72977d7a2739b0b" >
< Mapping XmlNamespace="myDemoActivities" ClrNamespace="myDemoActivities" Assembly="myDemoActivities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=23db3b03e98d33d7" >
<ns0:myWorkflow ID="myWorkflow" Initialized="InitVars" xmlns:ns0="myDemoWFLibrary">
<ns0:myWorkflow.Parameters>
<wcm:ParameterDeclaration Name="AppID" Type="System.String" Direction="In" xmlns:wcm="ComponentModel" />
</ns0:myWorkflow.Parameters>
<ns1:writeToXML AppID="*d2p1:ActivityBind(ID={/Workflow};Path=applicationID)" ID="writeToXML1" xmlns:d2p1="ComponentModel" xmlns:ns1="myDemoActivities" />
<ExceptionHandlers ID="exceptionHandlers1" xmlns="Activities" />
<EventHandlers ID="eventHandlers1" xmlns="Activities" />
<CompensationHandler ID="compensationHandler1" xmlns="Activities" />
</ns0:myWorkflow>
A couple of things i noticed:
1. The activitybind namespace is prefixed with '*d2p1'. Can the serializer not determine the orignal namespace
2. The namespace.class prefixes are missing from the root:
x:Class="myDemoWFLibrary.myWorkflow" xmlns:x="Definition" ID="SequentialWorkflow1" xmlns="Activities"
...but I see this is a known issue in a previous post.
Compared to my xaml file which was compiling and executing fine until i amended my original code to include code for binding the workflow params (see below):
< 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="myDemoActivities" ClrNamespace="myDemoActivities" Assembly="myDemoActivities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null" >
<
SequentialWorkflow x:Class="myDemoWFLibrary.myWorkflow" xmlns:x="Definition" ID="SequentialWorkflow1" xmlns="Activities" ><SequentialWorkflow.Parameters>
<wcm:ParameterDeclaration Name="AppID" Type="System.String" Direction="In" xmlns:wcm="ComponentModel" />
</SequentialWorkflow.Parameters>
<ns0:writeToXML AppID="*d2p1:ActivityBind(ID={/Workflow};Path=applicationID)" ID="writeToXML1" xmlns:wcm="ComponentModel" xmlns:ns0="myDemoActivities" />
<ExceptionHandlers ID="exceptionHandlers1" xmlns="Activities" />
<EventHandlers ID="eventHandlers1" xmlns="Activities" />
<CompensationHandler ID="compensationHandler1" xmlns="Activities" />
</SequentialWorkflow>
This fails to execute, and we are stumped as to where to go next!
If i remove the asterix from the start of the binding, the value is passed as a string (d2p1:ActivityBind(ID={/Workflow};Path=applicationID)) and written to my xml file.
Also, when I add the event handler for Initialized to set the value of the param to the root node (as per the generated xaml file does), it also fails. Private Sub InitVars(ByVal sender As System.Object, ByVal e As EventArgs)Me.applicationID = DirectCast(Me.Parameters("AppID").Value, String)
End Sub
Using VS.NET Beta 2 (VB.NET)
Any help much apriciated!
Thanks,
Steve Hearn

Problem passing parameters from workflow to custom activity using dynamicly compiled xoml workflow
ongsw
Thanks Angel!
However, I now get the following error on compilation:
"Activity 'writeToXML1' validation failed: Path 'applicationID' used to specify member for 'SequentialWorkflow1' is invalid. Path needs to point to valid member."
I also have this error in the designer (only when the workflow designer screen is open)
"Error 1 The variable 'AppIDProperty' is either undeclared or was never assigned."
Thanks!
Steve
PatrickDN
The problem now is that these fields/properties referenced in your new workflow exist in the already compiled workflow assembly, not in the new one you're creating. When you serialize the XAML, give it an x:Class, and compile again, you are essentially creating a new workflow, which should have its own code beside files (or CodeDom ccu's) defining its own fields/properties.
One thing you can try is keeping the serialized XAML from the compiled type (the one that references ns0:myWorkflow instead of SequentialWorkflow) and adding a new x:Class attribute with a different class name. This should result in the creation of a new workflow that inherits from your old one, with whatever activities/parameters you have added. Keep in mind that only public/protected members from the base class will be visible.
Thanks!
Angel
Newm
Hi Steve,
Looks like you're working on some neat stuff. I need the following details though:
"However, when i serialise out the instance to see the xaml that is created with the params and try to incorporate that in my own xaml to compile dynamically, the IDE throws a compiler error when i try to start the wf."
-I'm not quite sure what you mean here by "try to incorporate that in my own
xaml to compile dynamically"
-Also, what is the compiler error you are getting here Is it a compiler error or is
it a runtime error when you start the workflow (compilation succeeded)
"The activitybind namespace is prefixed with '*d2p1'. Can the serializer not determine the orignal namespace "
-This is fine. "d2p1" is an arbitrary XML namespace that is mapped to the
System.Workflow.ComponentModel assembly.
"This fails to execute, and we are stumped as to where to go next!"
-How does it fail Does it return an error during compilation or afterwards
when you have already compiled and are trying to execute What is the
error
Thanks!
Angel
markm2005
The problem is in this line:
<ns0:writeToXML AppID="*d2p1:ActivityBind(ID={/Workflow};Path=applicationID)" ID="writeToXML1" xmlns:wcm="ComponentModel" xmlns:ns0="myDemoActivities" />
The problem is that ActivityBind is prefixed with the namespace "*d2p1", but the end of the line defines ComponentModel as "wcm", which is the assembly that ActivityBind resides in. As a result, deserialization fails because it cannot resolve the ActivityBind type.
The above line should look like this:
<ns0:writeToXML AppID="*d2p1:ActivityBind(ID={/Workflow};Path=applicationID)" ID="writeToXML1" xmlns:d2p1="ComponentModel" xmlns:ns0="myDemoActivities" />
Thanks!
Angel
faktujaa
Hi Angel,
Thanks for the reply!
We are modeling a business process which will require some end-user intevention, to add/remove activities to fine tune the model to fit the business requirements.
We will create a library of workflows for the process(s) inside vs.net and compile them into a dll file. We then use the WorkflowMarkupSerializer to serialize the workflow and get the XAML definition for the workflow. A little bit of massaging on the output file is required to add the missing class atrribute to the designer generated xaml file (x:Class="myLibraryNamespace.myWorkflowClass" xmlns:x="Definition") as this appears to be a limitation of beta 1.
This compiled assembely is then strong named and installed in the GAC of the users pc. Activites are also created in much the same way, in that an activity library dll is complied, strong named and placed in the users GAC.
To edit the workflows, we have created a seperate application to host the designer. This uses the serialized output xaml and the compiled dll to allow users to load up a workflow definition and add/remove activities from the base workflow. Its 'fine tuning' rather than authoring completely new workflows.
Once they are happy with their fine tuning of the workflow, the definition is then serialized again using the WorkflowMarkupSerializer.
The xaml file, together with the compiled workflow library dll and the activity library dll are run through dharmas WorkFlowCompiler sample to compile and execute the workflow, which is where we are having problems.
<quote>
"However, when i serialise out the instance to see the xaml that is created with the params and try to incorporate that in my own xaml to compile dynamically, the IDE throws a compiler error when i try to start the wf".
</quote>
The xaml which is serialized out from our custom designer is different to xaml that is created when you use a code seperation workflow. I guess this is because the workflow was generated programmaticaly so there is no type other than the base type, which in this case happens to be a SequentialWorkflow.
<ns0:myWorkflow ID="myWorkflow" Initialized="InitVars" xmlns:ns0="myDemoWFLibrary">
So if i change the xaml to reference my namespace.class as below (including x:class fix)
<SequentialWorkflow x:Class="myDemoWFLibrary.myWorkflow" xmlns:x="Definition" ID="SequentialWorkflow1" xmlns="Activities" >
and add the params to be passed into the workflow:
<SequentialWorkflow x:Class="myDemoWFLibrary.myWorkflow" xmlns:x="Definition" ID="SequentialWorkflow1" xmlns="Activities" >
<SequentialWorkflow.Parameters>
<wcm:ParameterDeclaration Name="AppID" Type="System.String" Direction="In" xmlns:wcm="ComponentModel" />
</SequentialWorkflow.Parameters>
<ns0:writeToXML AppID="*d2p1:ActivityBind(ID={/Workflow};Path=applicationID)" ID="writeToXML1" xmlns:wcm="ComponentModel" xmlns:ns0="myDemoActivities" />
<ExceptionHandlers ID="exceptionHandlers1" xmlns="Activities" />
<EventHandlers ID="eventHandlers1" xmlns="Activities" />
<CompensationHandler ID="compensationHandler1" xmlns="Activities" />
</SequentialWorkflow>
I get the following error when I try to compile:
System.Workflow.ComponentModel.Compiler.WorkflowCompilerError
Error Number 347
"Could not deserialize object. The type '.ActivityBind' could not be resolved."
If i remove the asterix from the start of the temp d2p1 namespace, the workflow compiles without any errors, and I can see that the params are passed in ok as my test application subscribes to the WorkflowCompleted event and writes out the workflow instance id from the event args to an xml file, along with the string "d2p1:ActivityBind(ID={/Workflow};Path=applicationID)" - I only did this to test my params are actually being fed all the way through from the workflow to my activity.
Thanks again for your help Angel!