Accessing workflow instance members from WorkflowInstance (runtime event handlers)

Hi All,

Is there a way to retrieve a strongly typed reference to the actual running workflow from a WorkflowInstance instance

More details:

I have a runtime event handler (loaded, idled) that receives a WorkflowEventArgs parameter. In that method I would like to access some of the instance properties (DependencyProperties) of my own workflow class. The only object I have in that method is a WorkflowInstance with an InstanceId. So the question is, how can I get a MyWorkflowClass instance if I have an InstanceId

Thanks in advance.



Answer this question

Accessing workflow instance members from WorkflowInstance (runtime event handlers)

  • Ken98045

    This may not be the right thread to point this out, but for me tracking workflow instance data is by far the most poorly thought-out and hard to use part of WF (by hard-to-use I mean in terms of code maintenance and coupling, not the API itself). Most workflow applications require a straightforward way of viewing the current and historic states of workflow instances and activities. But all of the WF options for doing this are clumsy, complex and hard-to-maintain. The frequency with which this question is asked on this forum demonstrates how unintuitive these approaches seem to be. Why was it not possible to simply allow access to read-only workflow and activity instances/DTOs that would not lock the instances for update by other users A read-only constraint on activity objects loaded outside of the workflow instance would hardly be less confusing for developers than the current approach.

    I understand and appreciate the reasoning behind tracking+workflow locking+queuing/EDX etc. but it just doesn't feel like it was trialled with anything more than the smallest of WF applications. Tracking is fine for a simple audit trail, but if you want to get the current state of your custom properties in a strongly-typed data structure then you need to spend a lot of time and effort synchronising your custom Activities with your TrackingProfiles, TrackingExtracts, UserTrackingRecords and whatever you use to translate UserTrackingRecords into something more meaningful than a bunch of name/value pairs. Adding a subclassed workflow type or a new activity property requires edits to several classes just to ensure the data is properly tracked and retrieved. Not to mention the poor OOB tracking query support and the lack of utility methods e.g. getting the latest/current tracking record against a given activity. Of course you can implement a custom tracking service to try and overcome all these limitations, but who has time do that for real (& I don't mean the tinker-toy tracking service samples).

    P.S. how about an FAQ thread on this forum - this question (along with confusion over the WorkflowDefinition property) is among several that seem to show up here pretty regularly.

  • BeckyB

    I started a previous thread stating the same complaint. This is rediculous design (IMO).

    Honestly, I am not saying this to offend - but it is my perception - Stop paying attention to factories and patterns from every gall darn OO book on the market and let's explore this issue (matbe we need a NEW pattern)!!!!

    PLEASE !!

    Now that I demonstrated my frustration through capital letters, I cannot agree more: why do I have to add another "service" to query the state of an existing instance I understand that anything that the workflow must respond to, should use the eproper interfaces and messaging, but simply having an instance on a service running and wanting to know "what's up with it" should NOT require another service (OMG). let's say we have an instance of a service called:

    myService

    WHY - PLEASE - WHY

    Why, can I not simple get:

    myService.CurrentState

    Why

    This is STUPID!!.. or... am I totally not getting how this could "blow up" workflows

    Sorry, again, I am not trying to offend, but it makes no sense (from what little I do know) >>> if there IS a good reason, then, please, POST IT. I have always run off the theory of open discussion including any unnecessary emotional responses and that we should all be prepared that there is a "good" reason. Ya know: to coin a phrase, "throw it up in the air and see if it gets shot"

    It seems like many, many users are throwing the same question in the air and the reason/ response we get is "We have the Tracking Service". Okay, SO WHAT!

    Please, answer the "actual" question.

    What is the reason or reasons that instance properties of a workflow instance do not actually contain state information (anything actually intuitive and useful)

    Thank you!

    Again, I am not angry, but I am emotional and would like some serious consideration given to this topic because WF is not intuitive (to many users) when a separate service must be created to identify properties of a currently active workflow.

    TIA

    Trevor


  • Sai A

    sorry I was in a hurry and I didn't read the question as I should.

    the traditional way to achieve this is to use the Tracking Service



  • Jon Limjap

    I have a new sample that shows a very simple tracking service to get the current property values of a running workflow instance. The tracking service creates a profile so that as each activity closes, the tracking service gets sent a tracking record containing all of the property values of the workflow. It then stores these in a dictinary, so the host process (i.e. your external code) can query the service for the current properties.

    I hope this helps some people out, as I know this is frustrating area for people. In many cases, you should be able to plug this service in and use it without any/many modifications.

    Matt

    Read more and find the link to the source at: http://pluralsight.com/blogs/matt/archive/2006/11/25/42637.aspx



  • 2000MPH

    Hi,

    I don't have the sdk/doc/VStudio on my current pc so I cannot test it for the moment, but if that helps (in a hurry) I think you can use the GetWorkflowDefinition() which returns a template of the root Activity which is your workflow; if you get the type of this root activity->...

    Serge



  • AlexBB

    Hello Shelly and thanks for the reply. I really do understand messaging and communication, but I believe (or at least hope) that is not the way in my case.

    Let me just rephrase the question:

    In the runtime event handlers (loaded, idled) is the tracking service the only way to get more information about the workflow instance that was just loaded or idled So there I have a WorkflowInstance instance and I have to use the tracking service to access the properties and the fields of the running workflow

    Thank you again.

    Gyorgy


  • n3sachde

    Hello Serge,

    Thanks for the reply but unfortunately it does not work.

    There is a GetWorkflowDefinition() method, but it returns a workflow template and not the actual running instance. The properties of this returned template does not contain the value of my workflow instance. The template could be good to modify the workflow but it is not what I want now.

    So the case is still open, does anybody have any ideas

    Thanks,

    Gyorgy


  • fjcardoso

    Shelly,

    what about the Tracking Service

    Serge



  • slsjr

    Shelly,

    I'm also concerned about lack of access to the workflow instance. I understand why the workflow passivation feature requires that you hide the workflow instance, since it may not exist. However, passivation is not an important feature for my application and I would disable it (via http://blogs.msdn.com/advancedworkflow/archive/2006/05/19/602116.aspx). It's far more important for me to have a reflectable, and invokable instance of the workflow instance.

    So my question is, are there reasons beyond passivation that prevent exposure of the workflow instance Could Microsoft, in a future version, provide a back door to the workflow instance if the developer double promises never to activate the passivation feature

    Thanks.

  • 71EFBB98-D1FE-4eff-BAC5-F94AC74

    I definitely agree especially on the FAQ part.
  • merwy

    Messaging and tracking are indeed the only ways to access workflow fields and properties.

    Shelly Guo


  • SamuelS

    I actually like and enjoy WF and am happy to learn how to use it, but I am still not agreeing that 'read-only' properties could be provided without requiring the devloper to manually create a separate service. Frankly, the current messaging or communication model does not have to discarded to accomplish this.

    Please, consider:

    Is it possible for methods behind "read-only" properties of a workflow instance to instantiate the tracking service and retrive what it needs without the developer having to manually create all of the tracking dependant code I believe a good portion of the tracking service should be involked "behind-the-scenes" so that the model is intuitive and "user-friendly" and makes it "seem" that the properties are available as part of the workflow instance.

    I understand the need for separation of functionality as far as the "engine" goes, but complete isolation is not the way to go - IMO. This, to me, is like a grid control where there may be several "views" available and only one is currently selected to display the the "current" grid. A well designed grid would be "user-friendly" and expose a property or method to get the current row of the current view. A poor design (IMO) requires the user (developer) of the grid to determine which view is active, get that view, and then get the current row.

    I think the scenario I described with the grid has similarities to workflow instances and tracking services From my view, the tracking service is like the view for the grid and a poor design (IMO) makes a user get/ create the service, and retreive the tracking info for the current workflow instance manually. A great/ fantastic design (IMO) would simply do that "stuff" behind-the-scenes because the advantages are tremendous for the end-user. It seems to me that the model would not be broken and data would not be corrupted, but WF would then take into account (greatly) user-interaction, which, ultimately determines to ease-of-use and overall success of a product. Couldn't we eat our cake and have it too

    When I design applications, the end-user never cares how its accomplished (under-the-hood); they care how user-friendly the end-result is and that it does perform everything required. Many applications do everything required and then some but they fail miserably in "user-friendly' interaction and therein lies their demise. What happens or how it happens under-the-hood is simply less important than the perception of what happens from the end-user's perspective.

    What I believe the problem is ... no wait... that's not correct... it would be better phrased as... I believe there is an "opportunity" for WF and it relates to why I referred to "patterns" in my previous post. Developers often get locked into the patterns that drive the model efficiently and many developers are often satisified when the model performs all the required - core - elements, but (and very very importantly) they often forget, overlook, or simply don't address that many of the patterns need to be decorated with functionality that masks some of the isolation of resposibility such as having the workflow instance utilize some of the tracking internally so that the the model is as 'user-friendly' as possible.

    Did I make any sense

    TIA

    Trevor


  • Batikit

    Sorry you are frustrated. I believe the reason you cannot get those items directly is that it is important that the host not directly interact with the workflow instance and that the workflow instance not directly interact with certain runtime services. This is all driven by the way the threading and scheduling model of workflow behaves. It is important for the workflow to be able to persist (go out of memory) and have its threads managed by the scheduler. If the workflow has to be accessible to the host directly, this becomes more difficult. Since the scheduler is managing the workflow instance, having the host try to access the instance and possibly make changes to it or interact with it, adds all sorts of complexity to you the host writer on dealing with threading, synchronization etc.

    I realize this seems like a simple problem from the surface, but the goal is to make WF more accessible. Hopefully, now that there is an answer to how to deal with this, it will be less frustrating for people.

    Note that I do not work for Microsoft and these are my opinions. There may be other very good reasons why they chose this design.

    Matt



  • shunt

    No, you can not access the running workflow directly from the host. This is explicitly forbidden in order to pretect the integraty of the workflow state. Allowing the host to modify the property values in a workflow may result in inconsistency of the workflow state.

    The only way you can talk to a workflow is through messaging. You can do this using ExternalDataExchangeService. Use a HandleExternalEvent to receive the query. If you pass in an object reference, you can use that to return the result. Or you can use a seperate CallExternalMethod to return the result. Return a copy of the property value instead of a reference because the activity classes are not thread safe.

    You can also implement a custom root activity that creates a WorkflowQueue to listen to any query message. The queue is created when the root activity is initialized and destroyed when the root is closed. The root activity itself subscribes to the QueueItemAvaialble event. That's how I would do it (see code below).

    protected override void Initialize(IServiceProvider provider)

    {

    base.Initialize(provider);

    if (this.Parent == null || this.IsDynamicActivity)

    {

    // setup the queue for command queries.

    WorkflowQueuingService queueService = provider.GetService(typeof(WorkflowQueuingService)) as WorkflowQueuingService;

    WorkflowQueue queue = queueService.CreateWorkflowQueue(this.Name, true);

    queue.QueueItemAvailable += new EventHandler<QueueEventArgs>(OnQueueEvent);

    }

    protected override void OnClosed(IServiceProvider provider)

    {

    // delete the command query queue

    WorkflowQueuingService queueService = provider.GetService(typeof(WorkflowQueuingService)) as WorkflowQueuingService;

    WorkflowQueue queue = queueService.GetWorkflowQueue(this.Name);

    queue.QueueItemAvailable -= new EventHandler<QueueEventArgs>(OnQueueEvent);

    queueService.DeleteWorkflowQueue(this.Name);

    base.OnClosed(provider);

    }


  • Accessing workflow instance members from WorkflowInstance (runtime event handlers)