In this post I demonstrated how to create IronPython objects and call them from strongly typed .NET code. So suppose we want to do so with Windows Workflow Foundation where could we use this?

Well the most obvious place would be a runtime service. The example below uses a very simple message that needs to be displayed but it is easy to see how to same concept could be applied in other places.

But first the basics. I have created a very simple custom DisplayMessageActivity like this:

public partial class DisplayMessageActivity : System.Workflow.ComponentModel. Activity { public DisplayMessageActivity() { } public string Message { get ; set ; } protected override ActivityExecutionStatus Execute( ActivityExecutionContext executionContext) { IDisplayMessageService service = executionContext.GetService< IDisplayMessageService >(); service.Display(Message); return base .Execute(executionContext); } }

Next I have created a very simple workflow with only the DisplayMessageActivity and set the Message property to: “This is the message to show.”.

You might have noticed in the code above that I am looking for a service of type IDisplayMessageService. This is pretty simple as well and looks like this:

public interface IDisplayMessageService { void Display( string message); }

In this case I am using an interface but you could just as well use a concrete baseclass with virtual methods.

For the actual implementation I created two classes in IronPython, the first displays the message on the console while the second uses a MessageBox to display the same message. The IronPython source looks like this:

import clr clr.AddReference('PythonWorkflowConsoleApplication1') from PythonWorkflowConsoleApplication1 import IDisplayMessageService clr.AddReference("System.Windows.Forms") from System.Windows.Forms import MessageBox # Display all messages in the console window class ConsoleDisplayMessageService(IDisplayMessageService): def Display(self, message): print message # Display all messages using a Windows.Forms.MessageBox class MessageBoxDisplayMessageService(IDisplayMessageService): def Display(self, message): MessageBox.Show(message, 'IronPython')

Like in the previous example I first import the clr so I can set references to additional assemblies. Next add a reference to the PythonWorkflowConsoleApplication1 assembly. This is my sample application that contains the runtime service interface definition. With this reference set I can import the IDisplayMessageService interface so I can derive from it.

I included two implementations, lets first look at the ConsoleDisplayMessageService as this is the simpler of the two. All this does is use the Python print function to display the message on the console. The first parameter, self, is the current object, so this in C# or me in VB. We make sure this class derives from IDisplayMessageService by specifying this after the class name. BTW the lines starting with # are comments in Python.

The second class is MessageBoxDisplayMessageService and this actually uses a MessageBox to display the message from the workflow. First we need to add a reference to the System.Windows.Forms assembly and once that is done we need to import the MessageBox type. Once this is done we can use it like this:

MessageBox.Show(message, ‘IronPython’)

Simple enough right.

So now for the trick part, adding the IronPython runtime service to the workflow runtime.

The console main function is as follows:

static void Main( string [] args) { using ( WorkflowRuntime workflowRuntime = new WorkflowRuntime ()) { AddMessageService(workflowRuntime, DisplayMode .Windows); WorkflowInstance instance = workflowRuntime.CreateWorkflow( typeof (PythonWorkflowConsoleApplication1. Workflow1 )); instance.Start(); Console .ReadLine(); } }

With the AddMessageService() doing the actual work. Note the second parameter specifies which IronPython class to load.

So the AddMessageService looks like this:

static void AddMessageService( WorkflowRuntime workflowRuntime, DisplayMode mode) { string className; if (mode == DisplayMode .Console) className = "ConsoleDisplayMessageService" ; else className = "MessageBoxDisplayMessageService" ; ScriptRuntime runtime = PythonEngine .CurrentEngine.Runtime; ScriptScope scope = runtime.ExecuteFile( "DisplayMessageService.py" ); PythonType pythonType = scope.GetVariable< PythonType >(className); object service = runtime.Operations.Call(pythonType); workflowRuntime.AddService(service); }

The basics are the same as in my previous IronPython post. Depending on the display mode I make a choice of class to load and I use the same code as previous time to create the object. Finally I add it to the WorkflowRuntime as a runtime service. This last bit is easy as this accepts every object type as a valid service and only when we call the GetService do we check the actual type.

I used IronPython 2.0 Beta 4 for this example. More info about IronPython can be found here, the download of version 2 here.

Enjoy!

[f1]

[f2]