EventHandler won't fire in state machine when calling event from host

Hi,

I have written a simple state machine which is very similar to the order example comes with WWF Jan Lab Beta 2.

I created the following service

public class NavigationService : INavigationService

{

public event EventHandler<NavigationEventArgs> StartPageStart;

public void RaiseStartPageStartEvent(Guid instanceId)

{

if (StartPageStart != null) //StartPage is null when host calling RaiseStartPageStartEvent

{

StartPageStart(null,new NavigationEventArgs(instanceId));

}

}

In the state workflow, I have bound the "InterfaceType" and "EventName" to the service and StartPageStart Event.

The problem is when I calling the following code in the host (a window form application)

_navigationService.RaiseStartPageStartEvent(workflowInstanceId);

It won't trigger the state change. I traced throught the code and found

StartPageStart is null inside function public void RaiseStartPageStartEvent(Guid instanceId)

Does anyone have any suggestion about how to ping down the problem

Thanks a lot

chong



Answer this question

EventHandler won't fire in state machine when calling event from host

  • Delapena

    Hi Matt,

    this is the code written in various layers.

    UI is a Web Page:

    private WorkflowRuntime runtime = null;

    private Guid id = default(Guid);

    private AutomobileService.AutomobileService automobileService = null;

    private ManualWorkflowSchedulerService manualservice = null;

    protected void Page_Load(object sender, EventArgs e)

    {

    id = Guid.NewGuid();

    //Starting the Runtime.

    runtime = WorkflowWebRequestContext.Current.WorkflowRuntime;

    //Creating the Local Service.

    automobileService = new AutomobileService.AutomobileService();

    ExternalDataExchangeService externalDataExService = new ExternalDataExchangeService();

    runtime.AddService(externalDataExService);

    externalDataExService.AddService(automobileService);

    }

    protected void btnSave_Click(object sender, EventArgs e)

    {

    if (ValidateControls())

    {

    //Creating an Vehicle Object

    AutomobileObject.Vehicle newVehicleInstance = new AutomobileObject.Vehicle();

    newVehicleInstance.VehicleNumber = txtVehicleNumber.Text.Trim();

    newVehicleInstance.Damaged = Convert.ToBoolean(dropDamaged.SelectedItem.ToString());

    newVehicleInstance.Discount = Convert.ToDecimal(txtDiscount.Text.ToString());

    newVehicleInstance.Price = Convert.ToDecimal(txtPrice.Text.ToString());

    newVehicleInstance.Shade = (AutomobileObject.Color)(dropColor.SelectedIndex);

    newVehicleInstance.TypeOfVehicle = (AutomobileObject.Type)(dropColor.SelectedIndex);

    newVehicleInstance.YOM = Convert.ToInt32(dropYOM.SelectedItem.ToString());

    Dictionary<string,object> parameter = new Dictionary<string,object>();

    parameter.Add("VehicleInstance",((object)newVehicleInstance));

    runtime.CreateWorkflow(typeof(AUTOWF.AutomobileProcessingWorkflow), parameter, id).Start();

    runtime.GetService<ManualWorkflowSchedulerService>().RunWorkflow(id);

    manualservice.RunWorkflow(id);

    //Create a new 'Vehicle'.

    automobileService.RaiseNewOrder(id, newVehicleInstance.VehicleNumber);

    }

    }

    Local Service

    ///////////////AutomobileLocalService////////////////////////////////////////////////////////////////////////////////////////////////////

    [Serializable]

    public class AutomobileEventArgs : ExternalDataEventArgs

    {

    private string strCarNumber;

    public AutomobileEventArgs(System.Guid guid, string strCarNo)

    : base(guid)

    {

    strCarNumber = strCarNo;

    }

    public string CarNo

    {

    get

    {

    return strCarNumber;

    }

    set

    {

    strCarNumber = value;

    }

    }

    }//end of class 'AutoEventArgs'.

    [ExternalDataExchange]

    public interface IAutomobileService

    {

    event EventHandler<AutomobileEventArgs> New;

    event EventHandler<AutomobileEventArgs> Deleted;

    }

    //end of interface IAutomobileService.

    //////////////////////////////////////Implementing the Interface///////////////////////////////////////////////////////////////////

    public class AutomobileService : IAutomobileService

    {

    public AutomobileService()

    {

    }

    public void RaiseNewOrder(Guid guid, string carNo)

    {

    if (New != null)

    {

    New(null, new AutomobileEventArgs(guid, carNo));

    }

    }

    public void RaiseDeleted(Guid guid, string carNo)

    {

    if (Deleted != null)

    {

    Deleted(null, new AutomobileEventArgs(guid, carNo));

    }

    }

    #region IAutomobileService Members

    public event EventHandler<AutomobileEventArgs> New;

    public event EventHandler<AutomobileEventArgs> Deleted;

    #endregion

    /////////////////////////////////////////////Workflow///////////////////////////////////////////////////////////////////////////////////////

    Its a code seperated state m/c workflow and has only two states 'Created(Initial state)' and 'Deleted'

    Thanks.......


  • LuisLeitedaCosta

    When you register your local service do you do it the new Beta2 way, or are you still registering the old way

    The old way was to call AddService on the workflow runtime and add your local service. The new way is to create an instance of the ExternalDataExchangeService and add that to the runtime. Then, add your local service to the ExternalDataExchange service. This will add it to the runtime for you and does a bit more. I have seen event handlers not get hooked up if you don't use this method.

    Matt



  • Lorenzo778

    Hi there,

    I have the same problem I have followed the procedure to add the service to the ExternalDataExchangeService too but this has'nt worked .

    Also i'm using an ASP.Net application ,'HttpWebHostingModule' and a 'ManualWorkflowScheduler' but am not able to raise events on the workflow.

    A stateInitialization activity in the Initial workflow state gets executed though.

    Am I still missing somethiong here.....kindly throw some much needed "daylight"...

    Thanks,

    crp


  • pete_borg

    Hi, Matt:


    Thanks for the reply. That was the problem. I figured it out after comparing my code with the order example comes with Beta 2 lab.

    chong


  • Jason Wall

    Chong... email me your solution and I'll take a look.

    dennispi@nospam.microsoft.com (remove the nospam)



  • JulieD

    Are you using the RunWorkflow method on the ManualSchedulingService That is a pretty common problem in beta 2 with asp.net apps.

    Also, I have found that running the workflow from a test host might help you find problems that you can't find as easily in asp.net. The errors you get tend to be different and it is a little easier to debug the console host.

    If this isn't the problem, feel free to post the code you are using to run the workflow and raise the event.

    Matt



  • Trevor2006

    The main thing that jumps out at me is that you call RunWorkflow twice in a row on the ManualSchedulerService. You should only need to call this once, but I don't think it will cause you problems to call it more than once.

    The other thing I noticed is that you put the local service in the runtime on each page load. I would expect you to get an error here, but if not, it may be causing you problems. I would move this code to add your local service to an Application_OnStart method or something like it in the asax file.

    If you are interested, you can send me your project offline and I will take a look to see if I can get your event to fire. Other things I would look at would be the setup of the state machine to make sure it is ready for the correct event and the web.config file to make sure the correct services are configured.

    Matt



  • Selim Yucel

    Hi, Dennis:

    Thanks a lot for the help. I have sent you the solution as a zip file.

    Please let me know if you need more detail information.

    chong


  • PaulWelby

    Hi Crp2k4,

    You actually dont need to do any of the runtime setup on each page in an ASP.NET app.

    If you have a look at the Workflow's WebService Publishing wizard to see how you could setup a ASP.NET Webservice environment - mainly all done in the web.config.

    So for ASP.NET, what I do:

    (1) declare a global static 'runtime' variable that references the WF runtime engine (as these are hosted within your appdomain)

    (2) on the application_onStart event in the global.asax do your runtime initialisation there.

    Each page that uses the workflow doesnt have to start it all up and tear it down. This approach assumes that the majority of your pages will use the workflow in some way.

    Now for your problem:

    The part that doesnt look right for me is:

    you create the runtime as a page level variable and fire up your workflow that way (which is fine for a single page use), but then
    you grab the current workflow runtime from the webrequest context.

    My understanding is that this is only available if you're using the Workflow HTTP module handler - as the request has been intercepted prior to your page getting it, the custom handler has initialised the environment to make that work.

    Check a Workflow Webservice example for more detail (in the web.config)

    HTH,

    Mick



  • EventHandler won't fire in state machine when calling event from host