Steve1999

Hi,
I'm currently building a host (in a winservice with WCF interface) that will service any number of workflows. Part of my WCF interface is exposing to clients a general way to fire events, get states, etc.

When state machine workflows are built, you bind the events that trigger state changes to a event that will live on a ExternalDataExchangeService.

My question: since, at design time, in a state machine workflow you must bind the event to an interface, and that my host is generic, in a runtime sense, how do i build the host generically...to handle & fire any event that needs to be triggered for any workflow that our customer creates

My only idea is to abstract out the events into a separate type (and assembly), and load this assembly thru a WCF method to the runtime's services. And to require that our customers, when they define a workflow that exposes new types, they must call this WCF method to add the new events to the hosted runtime. Does this seem sensible


Re: Windows Workflow Foundation building a generic state machine host: handling events

Jon Flanders

I'm working on something like that right now for MS - although the release date isn't known at this time.

When hosting in WCF - I think about two things:

#1 - I think having a servicetype and a workflowtype is wrong - I think the host should be generic and be able to expose a workflow as a service without having to write a seperate type (this sounds like what you are doing). You can do this with a custom servicehost and objectinvoker.

#2 - I am working on a "layer" that will stand in for any ExternalDataExchangeService interface without having to write a seperate concrete type. I am doing this by using a RealProxy and a TransparentProxy.

I would think you would need some form of configuration is to load those new workflows.






Re: Windows Workflow Foundation building a generic state machine host: handling events

Steve1999

Hi Jon,

the workflows we're building are state machine workflows that dont need webservice inputs (and hence, i had not thought of exposing these workflows as service types). they simply wait for events like: (1) author has reviewed the document, (2) peer has countersigned the document, (3) supervisor has approved the document. These events come in from our client application.

So, I'm trying to build a generic host (in a winservice) that hosts these state machine workflows, and response to any number of events from our clients.

I wonder if I should be building the workflows to use webservice inputs (and thus, exposing them thru an objectinvoker, as you mentioned) instead of events (which require binding at design time to an event type). Given what i've described, do you think i should use webservice inputs instead of events

If you'd like to help (offline), please send email to steve.burkett (at) symyx.com Thanks! :)






Re: Windows Workflow Foundation building a generic state machine host: handling events

Roman Kiss

 

Steve1999,

 

Try the following design. It¡¯s based on the WCF/WF event interface contract between the Workflow and its consumer.

 

The following code snippet shows an example of the interface contract which represents a logical connectivity between the HandleExternalEvent Activity and the WCF Service/Client:   

 

namespace InterfaceContract

{

 [ExternalDataExchange]

 [ServiceContract(Namespace = "InterfaceContract.ITest,InterfaceContract")]

 public interface ITest

 {

   // WCF service

   [OperationContract(IsOneWay = true, Name="Event1")]

   void FireEvent1(object sender, ExternalDataEventArgs eventArgs);

       

   //   ...    

       

   [OperationContract(IsOneWay = true, Name="EventX")]

   void FireEventX(object sender, ExternalDataEventArgs eventArgs);

 

 

 

   // WF

   event EventHandler<ExternalDataEventArgs> Event1;

       

   //   ...

 

   // workflow

   event EventHandler<ExternalDataEventArgs> EventX;      

 }

}

 

Based on the above interface contract, the HandleExternalEvent Activity will create an event sink (workflow queue) for the selected event. Note, the event call is stored in the queue as a System.Runtime.Remoting.Messaging.IMethodMessage object.

 

The WF core has built-in the service layer (ExternalDataExchangeService) to intercept an event handler for generating an IMethodMessage object and storing it into the workflow queue - see the internal WorkflowMessageEventHandler class. This internal class (btw, It will be nice to have this class in public) has a public implementation of the EventHandler delegate:

                     public void EventHandler(object sender, ExternalDataEventArgs eventArgs);
 

As you can see, the above interface contract is using for WCF Service operation the same signature as the EventHandler delegate to fire an event. This service operation should be had the same logic like is done in the WorkflowMessageEventHandler.EventHandler method such as:

 

1.      GetWorkfow(eventArgs.InstanceId)

2.      Get EventQueueName

3.      Set eventArgs.Identity

4.      Create MethodMessage

5.      Send message to the Workflow queue

 

 

The Generic WCF Service for dispatching the source events to the target workflows (state machines) can be implemented based on the following service contract:

 

[ServiceContract]

public interface IFireEvent

{

  [OperationContract(Action = "*", IsOneWay = true)]

  void FireEvent(System.ServiceModel.Channels.Message message);

}

 

 

And the following is an example of the service implementation using the WorkflowInvoker from my article Workflow Adapter/Connector Pair:

 

public class WorkflowService : IFireEvent

{

  Type interfaceType = null;

  string eventName = string.Empty;

 

  public void FireEvent(System.ServiceModel.Channels.Message message)

  {

 

    XmlDictionaryReader reader = message.GetReaderAtBodyContents();

 

    // ExternalDataExchange contract

    interfaceType = Type.GetType(reader.NamespaceURI);

    eventName = reader.Name;

 

 

    // body of the event message

    reader.ReadStartElement();

 

    string sender =

     reader.ReadElementContentAsString("sender", reader.NamespaceURI);

 

    DataContractSerializer xs =

     new DataContractSerializer(typeof(ExternalDataEventArgs), "eventArgs", reader.NamespaceURI);

 

    ExternalDataEventArgs eventArgs =

     (ExternalDataEventArgs)xs.ReadObject(reader);

 

    reader.ReadEndElement();

 

    // enqueue message to the persisted workflow

    this.EventHandler(sender, eventArgs);

  }

 

  private void EventHandler(object sender, ExternalDataEventArgs eventArgs)

  {

    // workflow invoker

    RKiss.WorkflowRemoting.Invoker invoker =

      RKiss.WorkflowRemoting.WorkflowInvoker.Create(eventArgs.InstanceId);

 

    // dispatch message to the workflow

    object[] args = new object[]{sender, eventArgs});

 

    RKiss.WorkflowRemoting.MethodMessage msg =

      new RKiss.WorkflowRemoting.MethodMessage(interfaceType, eventName, args);

    

    invoker.SendMessage(msg as IMethodMessage);

  }

}

 

Note, the above implementation doesn¡¯t handle any exception or validation of the incoming event message and its dispatching to the workflow queue.

 

 

How it works:< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

  1. The client creates an ExternalDataEventArgs object and calling the WCF Service (for example WorkflowService) based on the ITest Service Contract.

          Note, the type of the custom ExternalDataEventArgs.WorkItem object must

          be declared in the config files (client/server) like it shown in the following example:

 

   <system.runtime.serialization>

    <dataContractSerializer>

      <declaredTypes>

        <add type="System.Workflow.Activities.ExternalDataEventArgs, System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

          <knownType type="InterfaceContract.MyWorkItem, InterfaceContract">

          </knownType>

        </add>

      </declaredTypes>

    </dataContractSerializer>

  </system.runtime.serialization>

 

  1. The event call is transported to the IFireEvent service and processed by the FireEvent operation. This operation has a responsibility to dispatch an event message to the target workflow sink (queue).
  2. The HandleExternalEvent Activity received an event message and updated the sender and eventArgs properties. 

 

 

Thanks

 

Roman