WF - Unit Testing: How to create Activity Type from XOML?

Damir Dobric Posts

Next talks:

 

    

Follow me on Twitter: #ddobric



 

 

Archives

Typically, one workflow can be started with the code similar to following one:

WorkflowInstance instance;
Dictionary<string, object> props = new Dictionary<string, object>();
props.Add("WorkflowArgument", "test");
instance = m_Runtime.CreateWorkflow(typeof(MyWorkflow), props, Guid.NewGuid());
instance.Start();

But, sometimes, you will be required to start a single activity. This sounds as some very simple and theoretical case, but at least when unit tests for the workflow have to be implemented, you will notice that this is not trivial as expected. Now, let's take a look how to start a single activity as UnitTest in VS:

[TestMethod]
public void TestMethod00()
{
  WorkflowRuntime runtime = new WorkflowRuntime();

  ManualWorkflowSchedulerService scheduler =
  new ManualWorkflowSchedulerService();

  runtime.AddService(scheduler);

  MyActivity activity = new MyActivity ();
  WorkflowInstance instance;
  Dictionary<string, object> props = new Dictionary<string, object>();

  props.Add("WorkflowArgument", "test");

  instance = runtime.CreateWorkflow(activity.GetType(), props, Guid.NewGuid());
  instance.Start();
  scheduler.RunWorkflow(instance.InstanceId);
}

As shown in example above, one activity can be started almost in the same way as the workflow. The only difference is that you have to a care by yourself about scheduling of the activity. For this purpose the ManualWorkflowSchedulerService is used. This service ensures that the workflow is started as blocking call in the same thread as the thread which has invoked the method RunWorkflow. Such scenario can be very useful for example in one ASP.NET application.

If you have some more sophisticated tests, you might create dynamically test workflows, which host your activity. In this case we do not deal with known types as in previous two examples (known types are in this case MyWorkflow and MyActivity). Moreover, it could be useful to manipulate XOML files and then to create the activity instance by deserializing of the XOML.
Following example shows a XOML which defines a workflow with one activity:

string m_Xoml = @"<ns:MyActivity xmlns:ns=""http://daenet.eu/workflow.activities""></ns:MyActivity>";

To be able to deserialize this XOML, somewhere in the assembly which contains the type MyActivity following snippet has to be pasted:

[assembly: XmlnsDefinition("http://daenet.eu/workflow.activities ", "Daenet.Workflow.Activities")]

This defines the mapping from namespace used in the code and XML namespace. After all, implement following method which does all magic. This method shows how to invoke the activity type from workflow described in pure XOML provided as string:

private Activity GetActivityTypeFromXoml(string xoml)
{
  XmlReader reader = XmlReader.Create(new StringReader(xoml));

  TypeProvider typeProvider = new TypeProvider(m_Runtime);
  typeProvider.AddAssembly(Assembly.Load("Assembly.Containing.MyActivity"));

  ServiceContainer container = new ServiceContainer();
  container.AddService(typeof(ITypeProvider), typeProvider);

  DesignerSerializationManager manager =
  new DesignerSerializationManager(container);
  manager.CreateSession();

  WorkflowMarkupSerializationManager serializationManager =
  new WorkflowMarkupSerializationManager(manager);

  Activity activity =
  new WorkflowMarkupSerializer().Deserialize(serializationManager, reader)
  as
 Activity;

  return activity;
}

To be sure that all works fine, try following code, which shows how to execute the activity created from XOML:

[TestMethod]
public void TestMethod00()
{
  Activity activity = GetActivityTypeFromXoml(m_Xoml);

  WorkflowRuntime runtime = new WorkflowRuntime();
  ManualWorkflowSchedulerService scheduler =
  new ManualWorkflowSchedulerService();

  runtime.AddService(scheduler);

  WorkflowInstance instance;

  instance = runtime.CreateWorkflow(activity.GetType(), props, Guid.NewGuid());
  instance.Start();

  scheduler.RunWorkflow(instance.InstanceId);
}

There is also one more example, which has been briefly described by Scott. Scott describes in his post how to start the workflow by passing of the reader build on the top of string containing the XOML. Following code snippet shows shortly how to do that:

XmlReader reader = XmlReader.Create(new StringReader(xoml));
instance = runtime.CreateWorkflow(reader, null, props);


Hope this helps you build better tests.


Posted Jul 31 2007, 11:01 PM by Damir Dobric
Filed under:

Comments

Andreas Erben's posts wrote WF - Unit Testing: Simple approach to Activity testing and improving the XOML loader.
on 08-01-2007 21:52

Usually I agree with Damir and his excellent posts. However, I cannot agree 100% with his post about

Damir Dobric Posts wrote Hosting BPEL Workflow
on 11-21-2007 15:40

While hosting the BPEL type of the workflow in Workflow Foundation you may get following error: &quot;The

K. Scott Allen wrote A Few Interesting Windows Workflow Links
on 01-21-2008 5:53

Igor emailed me for my thoughts about his SMTP server built with Windows Workflow. A link for the source...

BusinessRx Reading List wrote A Few Interesting Windows Workflow Links
on 01-21-2008 6:00

Igor emailed me for my thoughts about his SMTP server built with Windows Workflow . A link for the source

Yoot wrote Unit Testing custom Workflow Activities
on 04-13-2008 10:26

Unit Testing custom Workflow Activities

developers.de is a .Net Community Blog powered by daenet GmbH.