The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,639,104
since: 19 Jan 2005

Working with XOML-only Workflows that use Data Exchange Services

posted Fri 01 Sep 06
The ability to create portable, XOML-only workflows that you can store and transmit if it were simple data and then activate in a host application is pretty powerful. When you consider that you can use sequential workflows to drive thousands of different kinds of processes and you can use state machine workflows to model the most complex human-machine interaction workflows imaginabale - the ability to take those workflows and make them a distributable component is mind-blowingly cool.

Let's say you're designing an application that is a Windows Forms app that displays different forms at different times based on the logic and information contained within a workflow. To do this, you need to create an application that hosts the WF runtime, but you also need to create the data exchange interface and the data exchange class. The portable workflows, while they may not have any code-beside files, will reference the fully qualified namespace name of the Interface. The main issue here isn't a technical one its a question of design. How do you design a codeless workflow so that it can dictate what screen the host application is displaying at any given time? To keep things as loosely coupled as possible, I recommend adding an event to the Data Exchange service that can be fired by the workflow called something like OnScreenTransitionRequest. This event will signal the host application that the workflow would like the screen to transition from whatever is currently displayed to the indicated screen, using an indicated effect like a wipe, swirl, slide, or fade.

Here's the ISampleDataExchange interface and the SampleDataExchange class that implements the interface:

using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow;
using System.Workflow.Activities;

namespace WorkflowConsoleApplication4
{
    public delegate void SignalTransitionDelegate(string newXaml, string effect);

    [ExternalDataExchange]
    public interface ISampleDataExchange
    {
        event SignalTransitionDelegate OnSignalTransition;

        void SignalPageTransition(string newPage, string effect);
    }

public class SampleDataExchange : ISampleDataExchange
{
   #region ISampleDataExchange Members

   public event SignalTransitionDelegate OnSignalTransition;

   public void SignalPageTransition(string newPage, string effect)
   {
     if (OnSignalTransition != null)
      OnSignalTransition(newXaml, effect);
   }

   #endregion

}
}

The next thing you need to do is to be able to load the Workflow XOML from disk and hand it to the workflow runtime, as well as attach the Data Exchange Service in such a way that the workflow can properly find it:

#region Using directives

using System;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Runtime.Hosting;
using System.Workflow.ComponentModel.Compiler;

#endregion

namespace WorkflowConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs e) {waitHandle.Set();};
                workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs e)
                {
                    Console.WriteLine(e.Exception.Message);
                    waitHandle.Set();
                };

                XmlReader xr = XmlReader.Create(@"..\..\SampleWorkflowStandalone.xoml");
                try
                {
                    ExternalDataExchangeService eds = new ExternalDataExchangeService();
                    workflowRuntime.AddService(eds);
                    SampleDataExchange sampleService = new SampleDataExchange();
                    eds.AddService(sampleService);

                    WorkflowInstance instance = workflowRuntime.CreateWorkflow(xr);
                    sampleService.OnSignalTransition +=
new SignalTransitionDelegate(sampleService_OnSignalTransition);                  
                    instance.Start();

                    waitHandle.WaitOne();
                    Console.WriteLine("Workflow done.");
                    Console.ReadLine();
                }

                catch (WorkflowValidationFailedException ex)
                {
                    StringBuilder errors = new StringBuilder();
                    foreach (ValidationError error in ex.Errors)
                    {
                        errors.AppendLine(error.ToString());
                    }
                    Console.WriteLine(errors.ToString());
                    Console.ReadLine();                   
                }             
            }
        }

        static void sampleService_OnSignalTransition(string newPage, string effect)
        {
            Console.WriteLine("Workflow signaled page transition to {0} using {1} effect.",
newXaml, effect);
        }
    }
}
And finally here is the standalone workflow XOML that makes use of the data exchange interface to call the SignalPageTransition method after a time delay ( don't try and copy the XOML from here, I've added line breaks that will screw up the parser to make it easier to read on the blog):

<SequentialWorkflowActivity x:Name="SampleWorkflow" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"
xmlns:sampleapp="clr-namespace:WorkflowConsoleApplication4;
Assembly=WorkflowConsoleApplication4">
    <DelayActivity TimeoutDuration="00:00:05" x:Name="pause1" />
    <CallExternalMethodActivity x:Name="ShowNewPage"
InterfaceType="{x:Type sampleapp:ISampleDataExchange}"
MethodName="SignalPageTransition">
        <CallExternalMethodActivity.ParameterBindings>
            <WorkflowParameterBinding ParameterName="newPage">
                <WorkflowParameterBinding.Value>
                    <ns0:String
xmlns:ns0="clr-namespace:System;Assembly=mscorlib,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">secondpage.xaml</ns0:String>
                </WorkflowParameterBinding.Value>
            </WorkflowParameterBinding>
            <WorkflowParameterBinding ParameterName="effect">
                <WorkflowParameterBinding.Value>
                    <ns0:String
xmlns:ns0="clr-namespace:System;Assembly=mscorlib,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">supercool-fadeorama</ns0:String>
                </WorkflowParameterBinding.Value>
            </WorkflowParameterBinding>
        </CallExternalMethodActivity.ParameterBindings>
    </CallExternalMethodActivity>
</SequentialWorkflowActivity>

And finally, here's the output of the application that dynamically loads the XOML workflow and hooks it up to a known data exchange service:
Workflow signaled page transition to secondpage.xaml using supercool-fadeorama effect.
Workflow done.

I think anybody reading this blog is probably going to realize the potential use for this technology and hopefully you'll go out and start writing some amazing code right now.
I mean it. Start coding.
Now.

tags:            

links: digg this    del.icio.us    technorati    reddit




Tag Related Posts

Will Silverlight be DOA?

Mon 16 Apr 07 8:02 P GMT-05

Exploring the MVC Pattern in WPF

Tue 10 Apr 07 12:51 P GMT-05
tags:                      

WPF Bindings == WTF Bindings?

Mon 12 Mar 07 6:31 P GMT-05

Cocoa Bindings vs. WPF Binding

Thu 15 Feb 07 5:41 P GMT-05
tags:                

WPF Bumper Stickers

Tue 12 Dec 06 7:32 P GMT-05

Ulysses Agenda Makes Redmond Developer News

Wed 29 Nov 06 7:10 P GMT-05
tags:                

Is the continuous beta the new model for Vista?

Tue 21 Nov 06 8:51 P GMT-05
tags:              

Ulysses Agenda : First Cut Networking Design

Thu 14 Sep 06 12:46 A GMT-05
tags:                  

First Impressions of Windows Vista RC1

Thu 07 Sep 06 1:30 P GMT-05
tags:                      

Localizing a WPF Application

Tue 22 Aug 06 11:39 A GMT-05
tags:            

WPF Slide Show and Photo Album

Fri 18 Aug 06 6:48 P GMT-05

Is Windows Workflow Foundation Too Complex?

Fri 18 Aug 06 12:15 P GMT-05

ADO.NET Entity Framework Announced Today!

Wed 16 Aug 06 11:08 A GMT-05

Extending your Applications with MAF/VSTA - Part III

Fri 21 Jul 06 12:30 A GMT-05
tags:            

Extending your Application with MAF/VSTA AddIns

Thu 20 Jul 06 1:51 A GMT-05
tags:            

July CTP is out... yay.

Tue 18 Jul 06 6:34 P GMT-05
tags:    

.NET Framework 3.0 June CTP is out!

Fri 23 Jun 06 6:23 P GMT-05
tags:                

Tech-Ed 2006 - Session Reviews

Tue 13 Jun 06 6:22 P GMT-05
tags:                    

WPF/XAML and LINQ - A match made in heaven

Tue 06 Jun 06 11:32 A GMT-05
tags:                  

Windows Vista Beta 2 - Redeeming Qualities

Tue 30 May 06 2:29 P GMT-05
tags:        

Windows Vista Beta 2 - Day 2

Fri 26 May 06 11:50 A GMT-05
tags:            

Windows Vista Beta 2 - Day 1

Thu 25 May 06 1:01 P GMT-05
tags: