Partilhar via


Windows Workflow Foundation (Basics): How to handle external events and to trigger state transitions using a HandleExternalEvent activity

 

MSDN's description for a HandleExternalEvent reads as "Defines a workflow communication activity that is used to handle an event that is raised by a local service". In this blog I will try to expand on that definition.

Imagine a simple state machine representing a moving (state = Moving) or non-moving (state = Stopped) vehicle. For simplicity, let's assume that the vehicle can only start moving if the driver accelerates and it stops when the brakes are applied:

WF's state machine runtime allows services to raise events which can be handled by the state machine. In other words, a local service could perhaps communicate with a state machine via this route.

Let’s create a simple service project which will allow us to raise both the accelerate and brake events:

- Create an empty class library called VehicleService
- Inherit from ExternalDataEventArgs and mark the inherited class as serializable (it must be marked as serializable in order to be sent to the state machine):

[Serializable]
public class MovementChangeEventArgs : ExternalDataEventArgs
{
   private MovementChangeType _movementChangeType;
   public MovementChangeType MovementChangeType
   {
      get { return _movementChangeType; }
      set { _movementChangeType = value; }
   }

 

   public MovementChangeEventArgs(Guid instanceId, MovementChangeType
movementChangeType) : base(instanceId)
   {
      _movementChangeType = movementChangeType;
      this.WaitForIdle = true;
   }
}

public enum MovementChangeType
{
   Brake,
   Accelerate
}

- Create an interface which can be shared by both the local service (the service which has the responsibility for raising the event) and the state machine.
- Add only a single event to that interface

[ExternalDataExchange]
public interface IVehicleService
{
   event EventHandler<MovementChangeEventArgs> MovementChanged;
}

- As you can see above, the interface is marked with the ExternalDataExchangeAttribute attribute which flags the interface as a local service used for data exchange purposes.
- The next step is to implement the IVehicleService interface:

public class VehicleService : IVehicleService
{
   public void RaiseEvent(MovementChangeEventArgs args)
   {
      EventHandler<MovementChangeEventArgs> movementChanged = MovementChanged;
      if (movementChanged != null)
      {
         movementChanged(null, args);
      }
   }
   public event EventHandler<MovementChangeEventArgs>MovementChanged;
}

This interface now can be registered with the state machine. For this, you will need a HandleExternalEvent activity as the first event driven activity within the workflow of both the stopped and moving states:

- VehicleService class library must be referenced by the workflow project
- Go to the stopped state and drop a HandleExternalEvent activity as the first item within the event driven workflow. You will also need to set the following properties on this activity:
   o InterfaceType: IVehicleService
   o EventName: MovementChanged
- Now attach an event handler to the Invoked event of this activity which is called when the MovementChanged event is invoked. At this stage, you have a number of options open to you. One option is to keep the result of the event using a local property. You could perhaps add an IfThenElse activity followed by a SetState to your workflow which could trigger a state transition based on that local property.

The very last step is to make the workflow runtime aware of the service:

WorkflowRuntime workflowRuntime = new WorkflowRuntime();
ExternalDataExchangeService dataExchange = new ExternalDataExchangeService();
workflowRuntime.AddService(dataExchange);
VehicleService vehicleService = new VehicleService();
dataExchange.AddService(vehicleService);

You can now simply raise events by calling the RaiseEvent method of the vehicleService instance:

vehicleService.RaiseEvent(
new MovementChangeEventArgs(instance.InstanceId,
       MovementChangeType.Brake));

Please let me know what you think about this blog entry.

Comments

  • Anonymous
    December 27, 2007
    I have gone through the beautiful explanation .One clarification I want is that you have told to "make the workflow runtime aware of the service”. You have also showed the code .But my question is where to write this code ? It would be helpful if you answer this query.

  • Anonymous
    December 27, 2007
    Vikas, you need a workflow runtime to run your workflow for you. The service needs to be added to the runtime and it is usually done at the same time as you create the runtime. The runtime can be created anywhere in the host application. For instance it can be included in the Main method of a console app.

  • Anonymous
    January 02, 2008
    Hi Pedramr,  Thank you very much for responding to my query.Now I am having a different problem. As per your explanation, Now I am using a class library and a service  for some workflow application(Bug tracker).This class library should be placed in the GAC of sharepoint server. So it is clear that it is not an console application. Now where to write the code for "making the workflow runtime aware of my service"

  • Anonymous
    October 17, 2008
    where would i put this & please explain the  instance.InstanceId . Do I keep the vehicleService in a session from b4 .... come on finish it off now u have done a really good article!! vehicleService.RaiseEvent(   new MovementChangeEventArgs(instance.InstanceId,       MovementChangeType.Brake));

  • Anonymous
    January 14, 2009
    The comment has been removed

  • Anonymous
    April 23, 2009
    hi, I have created the sample state machine workflow in asp.net in VB code, with two states. the first state has state initialization and event driven activity, and the second state has state initialization. when start the workflow, it works fine at the initial state. when i raise a event using the handle external event activity it doesn't move to next state. I know that i have made a mistake, but couldn't able to trace. could you help me. Thanks in advance Venkatesh

  • Anonymous
    April 23, 2009
    hi, I followed the instructions given above but, in asp.net by vb code, it could able move to the next state. any one can help me thanks in advance Venkatesh

  • Anonymous
    March 25, 2010
    hi, I have created the sample state machine workflow in asp.net, with three states. the first state include handle external activity,code activity and call external activity, and the second state has handle external event. when start the workflow, it works fine at the initial state. when i raise a event using the handle external event activity in second state,the event has the value null.any one can help me Thanks in advance

  • Anonymous
    August 06, 2014
    hi, I have created the  state machine workflow , the second state has handle external event. when start the workflow, it works fine at the initial state. when i raise a event using the handle external event activity in second state,the event has the value null Thanks in advance