Ask a questionAsk a question
 

QuestionHow to use a workflow to drive the UI?

  • Thursday, October 08, 2009 6:21 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I've looked at a number of articles and threads that discuss using WF with ASP.NET sites to control page flow.  My situation appears to be unique and I am looking for as much guidance as I can.

    I have a business function that is easily represented as a sequential workflow.  In this workflow, there are many conditions that determine how the process executes.  These conditions can be triggered by user settings, system configuration and/or data input by the user, etc.  The workflow itself has been broken down into a series of composite activities, each with their own set of activities.

    My dilemma is that this workflow needs to drive the user-interface.  In other words, there are steps in the workflow that instruct the UI what to display.  For instance, we may need to prompt for certain data at a given point before moving on.  What makes this complicated, and unique from the articles I've read, is that we need to support multiple UI technologies such as ASP.NET, Silverlight and Windows Forms.  We want all of these client applications to follow the same workflow so we want to find away to use this workflow as the navigation engine for the applications.  I'm just not sure what would be the most effective approach.

    Keep in mind that the workflow can't be tied to a particular UI technology.  In the articles I've read, the workflow has knowledge of the page names, for instance.  I'm looking for something as generic as possible that can be used with any UI technology.

    Any suggestions?

All Replies

  • Thursday, October 08, 2009 7:11 PMRyan Vice Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    You have a few options. Basically you want to use one of the available means of communicating from WF instances (WFIs) to clients (WCF, Web-Services, ExternalDataExchange, CustomActivity, ect...). Pick whatever makes the most sense for your architecture and then add a layer to your application that takes calls from your WFIs and that then allows your UI technology of choice to get the data it needs. This could possibly happen by the UI subcribing to a DLL events that get raised, using publish\subscribe pattern or by updating a DB and then having the UI hit the DB to get it's data. You really have a few options here. If any of these seem good maybe you could flesh out the direction you are wanting to go more and if you get stuck post up what you got for feedback.


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.
  • Friday, October 09, 2009 5:29 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I guess I'm looking for something a little more tangible.  I don't know enough about any of those approaches (ExternalDataExchange, etc.) to know what would work best for my situation.  Let me give you a use case that might spur further insight...

    I have a feature that consists of a series of "prompts" culminating in a service call to perform the requisite operation on the server.  So my page flow would be something like:

    1. Do we display prompt 1?  (Check the user's profile and configuration settings)
    2. If yes,
      1. Display prompt 1
      2. Is user input valid?
        1. If not,
          1. Display error message
          2. Re-display prompt 1
    3. Display prompt 2

    The highlighted items represent where we tell the UI what to display.  In readible terms, we first check if we are to display the first prompt.  If so, we enter a sub-workflow that includes validating the user input and displaying confirmation or error messages based on what was entered.  If we do not display the prompt or after we receive valid user input, we move on to the next prompt.

    Keep in mind that my UI does not necessarily include Next and Previous buttons for navigation.  Page flow is determined by settings and user inputs.

    So, what is the best way for me to handle this without coupling to a particular UI technology?

     

  • Friday, October 09, 2009 5:37 PMRyan Vice Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    It depends on how you want to communicate from the workflows to the clients. What's your preference? You can use Web-Services, WCF workflow services, or ExternalDataExchange service (most likely if your web-server was on the same machine as your WF server).

    I'd guess since you want it to be UI agnostic that you'd want to use either web-services or workflow services to communicate.

    Once you decide on what technology you want to use then you'd use the activities that allow you to communicate via that techonolgy to drive your WF. The details of how you'd push and pull data depends on this choice, so please say what's your preference and then I can help you flesh out the rest.
    If my response answers your question, please mark it as the "Answer" by clicking that button above my post. My blog: http://www.RyanVice.net/
  • Friday, October 09, 2009 9:58 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I guess I don't know enough about the choices to have a preference.  It does seem like ExternalDataExchange is pretty complicated to implement and the idea of a service-based solution would be better so we can support Silverlight clients.  That said, I'm open to your recommendations.

    My goal is for the UI to simply to ask whatever is there (service, controller, manager, ...) what to do and have the workflow respond with directions.  In other words, the UI initiates the workflow (somehow) and is configured by the workflow.  In the previous example, if the workflow says to display prompt 1, that occurs; otherwise, prompt 2 is displayed.

    The CallExternalMethodActivity would require some knowledge of the UI within the workflow, but I suppose that could be handled by passing in an interface as a dependancy property for the workflow. But this seems complicated and tied to the External Data Exchange feature where we have to register services, etc. in order to make it work.

    Does that narrow which options would work?

     

  • Saturday, October 10, 2009 4:25 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Okay, I think I've coalesced some of these ideas and have a better context for my question(s) now.

    At a high level, I need the workflow to define what pages to display.  So, the workflow with contain activities such as SelectValue1Activity and SelectValue2Activity.  Each of these activities are sub-workflows which contain logic to determine whether we need to prompt the user for the value or not.  If, for example, we determine that the first prompt is not needed, the SelectValue1Activity will simply return and the workflow will proceed to the SelectValue2Activity.  On the other hand, if we do need to prompt for the first value, I need some way to tell the UI to do so.

    So, I see this as a two-pronged problem.  My UI needs to be flexibile enough to respond to instructions from the workflow telling it which page/screen/window/form to display AND I need the UI to provide the required information back to the workflow so it can proceed to the next step.

    Does that help scope the problem better?
  • Monday, October 12, 2009 7:12 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Okay, I've talked the situation over with my team and I think we are looking for a solution that will allow our workflow to raise an event when we want to prompt the user and have some type of callback method for the UI to pass the response back to the workflow.  The event must support custom arguments so that we can pass the information required by the UI to display the correct prompt.  The callback also has to allow us to pass anything back to the workflow - so to speak.

    We want to use an event because the workflow should not be coupled in any way to the UI client that is interacting with the user.  And, we don't want to declare a separate event for each communication point because that would be overwhelming and the app is extensible so having a single event that the client listens to will work great.

    Using this approach, our UI client will initiate the workflow and listen for this event.  When raised, the arguments will contain an item that tells the UI what should be displayed/prompted.  The UI will render the appropriate page/form to the client then use the callback method to submit whatever data was obtained from the client back to the workflow which will then proceed to whatever the next step is.

    Does one of the suggested options, such as ExternalDataExchange, fit the bill?
  • Monday, October 12, 2009 7:25 PMRyan Vice Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    What you'd want to do is create a WorkflowClient component that will do 2 things

    1 - Expose events from your WFIs to your client
    2 - Expose an interface for raising events into your WFIs

    If you are running ASP.Net on the same box as WF server then you could host the WF runtime in your ASP.Net application by putting your hosting code in Global.asax ApplicationStart event. But I do believe that earlier you mentioned "should be able to work with any UI." Allowing this to work with any UI and\or not wanting to host in ASP.Net (delay timers can be an issue when the application shuts down due to idle time) then you'd need to have a way of communicating between WorkflowClient and the WorkflowRuntime. Again with the same options I mentioned above.

    In our system we use MSMQ to communicate from the the WF client to the WF runtime and we hosted our WF runtime in a windows service. For your needs this kind of appoach might be overkill. I'd probably recomend looking into using workflow services. This would allow you too host the WF runtime in your WCF services and then you can do 2 way communications between WF client and sever through WCF. I haven't done this but this video describes the basics:

    http://www.microsoft.com/uk/msdn/screencasts/screencast/285/WF-V35-Building-WCF-Services-Using-Workflow-Foundation.aspx

    Another option is to use straight Web Services as described here:

    http://www.microsoft.com/uk/msdn/screencasts/screencast/285/WF-V35-Building-WCF-Services-Using-Workflow-Foundation.aspx

    And if you are open to hosting in ASP.Net and don't mind the tight coupled design or DelayActivity issues then see my blog for details on communicating to and from a client using ExternalDataExchange here:

    http://www.ryanvice.net/uncategorized/using-externaldataexchange-service-in-wf-3-5/ (excuse the stretched images, I'm working on sorting that out).


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post. My blog: http://www.RyanVice.net/
  • Tuesday, October 13, 2009 3:03 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Ryan,

    The first two links both reference the same presentation.  Was that intentional?

    At first glance, the ExternalDataExchange approach works perfectly except for a Silverlight client which I presume requires us to have a service interface since I don't believe WF is supported within the Silverlight application.  Looking into Workflow Services, the video and MSDN documentation, it looks like we are stuck with a more traditional Duplex conversation rather than having the UI client simply respond to an event from the workflow.  I guess I need to understand how the conversation would work when there is much back-and-forth during the workflow's execution.

    For instance, I can see having a service method StartWorkflow() that we call from the UI client to kick-off the process.  The UI would then wait for a response that will indicate the prompt to display.  I'm not sure how to make this work within the workflow, however.  And, it seems like I would need a separate service method for each user input I need to provide back to the workflow.

    I really liked the idea of maintaining a tight relationship between the "workflow event" (CallExternalMethod) instructing the UI what to display that the "UI event" (HandleExternalEvent) that would contain the user's response.  It seems that the request/response approach via the WCF service interface decouples this a bit.

    Does that make sense?

    I need something robust and flexible so that I can easily modify my workflow without having to change the service interface.  Is there some way I can emulate the convenience/compactness of the ExternalDataService in a WCF service interface?

  • Tuesday, October 13, 2009 5:01 PMRyan Vice Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Second link should be: http://www.microsoft.com/uk/msdn/screencasts/screencast/25/Windows-Workflow-Foundation-Exposing-Web-Services.aspx

    And yes, that was why I was recomending WCF. It would allow for you to decouple the client and server out the box. Handling of a coversation in WCF is done through context and I believe the video I posted covers that. Give it a watch and see if that can help you get going. Then all you'd need to do is implement WCF calls from the client that maintain context.

    As far as needing a seperate method for each call is concerned, you could easily design a solution that would be more generic where you have a method like RaiseEvent() that you then pass arguments too that you can analyze on the WF side of the fence. I demostrate passing a custom event args through ExternalDataExchange on my blog post that I linked and the basic concepts would be the same. You'd pass some data via WCF and then bind that data to a base class member and then write conditional logic that analyzes that data and reacts appropriately.

    Also, there are tons of other great videos on workflow techniques here: http://msdn.microsoft.com/en-us/netframework/wf-screencasts.aspx
    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.

    My blog: http://www.RyanVice.net/
  • Tuesday, October 13, 2009 5:49 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Ah, that link helped me a bit more.  Now I think I can put my finger on where the idea of WCF services is falling apart for me.

    Our pageflow logic is such that each service call made by a client into the workflow must have a response that tells them what to do next.  So in the example way above, when the client calls our StartWorkflow() service method, that method must response with instructions to display Prompt1 or Prompt2.  When that happens, the workflow must wait until we get a response - from whichever prompt - then move on to the next step.  This means that I will have to place a ton of logic with the ReceiveActivity for the service method call so that I can respond with the appropriate information.  I am envisioning this getting quite complicated.

    I would paste in a diagram of our logic but I don't see how that's possible here, so bear with my text description...

    1. At the top of my workflow, I would have a ReceiveActivity listening for calls to the StartWorkflow() service method.
    2. Next I would have a condition to determine if we are prompting for Input1.
        A. If we are,
            i. We set the return value for the StartWorkflow() service method to instruct the UI to display the prompt for Input1.
            ii. Next, we have another ReceiveActivity listening for calls to some other service method that the client will use to send the user's input back to the workflow
            iii. Then we have a condition that validates the user's input
            iv. If valid,
                a. We go to step 3
            v. Otherwise,
                a. We set the return value to indicate that an error has occurred
                b. We loop back to step 2.A.ii.
        B. Otherwise, we auto-fill Input1
    3. Then we have a condition to determine if we are prompting for Input2
        A. If we are,
            i. We set the return value for the StartWorkflow() service method to instruct the UI to display the prompt for Input1.
            ii. Next, we have another ReceiveActivity listening for calls to some other service method that the client will use to send the user's input back to the workflow
            ...

    Is this the right way to handle this?  Can I use the same service method for multiple ReceiveActivities such as 2.A.ii and 3.A.ii?

  • Thursday, October 15, 2009 8:24 PMSonOfPirate Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Okay, one more post to try and get my approach squared away...

    Let's focus on an ASP.NET client to keep things simple.  In this case, the user browses to my application and the app calls through my WCF interface to start my workflow/pageflow.  The workflow processes my business logic until it determines what information needs to be obtained from the user before it can continue.  While this is happening, the ASP.NET page needs to be in a wait state - that's problem #1.

    Problem #2 is how the workflow communicates back to the client.  I see the following options:

    1. The service method used to start the workflow returns an object that instructs the client what page to display.  Postbacks would then call a different service method to pass the user's input into the workflow which would have the same return type.  Because this would amount to a synchronous service call, the client app naturally blocks until the method returns.  This would be the simplest from the client's perspective but I'm worried that it complicates the workflow because the ReceiveActivity would have to span all of the business logic required to generate a response.  This could be problematic when the logic that determines the return value is outside the scope of the workflow or activity that contains the ReceiveActivity.  It is for this reason that I think this option won't work for us.

    2. The service method used to start the workflow includes a callback contract that allows the workflow to call a method in the client directly.  Perhaps I can use the ExternalDataExchange service between the WCF service and workflow so CallExternalMethod can be used to call the callback.  Because this is an asynchronous call, the client will have to block somehow while it waits for the workflow to callback.  I could then use the same callback contract for calls made when the page is posted back.

    3. Similar to option #2, I could use a duplex channel between the client and the service.



    I think the biggest problem I have putting this subject to rest is the absence of any examples, articles, posts, etc. that demonstrate a conversation with a workflow that goes beyond a single exchange.  In my case, I need to be able to have a long-running conversation with multiple exchanges back-and-forth.  I can't imagine that I'm charting new territory here!
  • Friday, November 06, 2009 2:39 PMRyan Vice Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    What you'd want to do is create a WorkflowClient component that will do 2 things

    1 - Expose events from your WFIs to your client
    2 - Expose an interface for raising events into your WFIs

    If you are running ASP.Net on the same box as WF server then you could host the WF runtime in your ASP.Net application by putting your hosting code in Global.asax ApplicationStart event. But I do believe that earlier you mentioned "should be able to work with any UI." Allowing this to work with any UI and\or not wanting to host in ASP.Net (delay timers can be an issue when the application shuts down due to idle time) then you'd need to have a way of communicating between WorkflowClient and the WorkflowRuntime. Again with the same options I mentioned above.

    In our system we use MSMQ to communicate from the the WF client to the WF runtime and we hosted our WF runtime in a windows service. For your needs this kind of appoach might be overkill. I'd probably recomend looking into using workflow services. This would allow you too host the WF runtime in your WCF services and then you can do 2 way communications between WF client and sever through WCF. I haven't done this but this video describes the basics:

    http://www.microsoft.com/uk/msdn/screencasts/screencast/285/WF-V35-Building-WCF-Services-Using-Workflow-Foundation.aspx

    Another option is to use straight Web Services as described here:

    http://www.microsoft.com/uk/msdn/screencasts/screencast/285/WF-V35-Building-WCF-Services-Using-Workflow-Foundation.aspx

    And if you are open to hosting in ASP.Net and don't mind the tight coupled design or DelayActivity issues then see my blog for details on communicating to and from a client using ExternalDataExchange here:

    http://www.ryanvice.net/uncategorized/using-externaldataexchange-service-in-wf-3-5/ (excuse the stretched images, I'm working on sorting that out).


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post. My blog: http://www.RyanVice.net/

    The path to the article I posted is now: http://www.ryanvice.net/wf3-5/using-externaldataexchange-service-in-wf-3-5/
    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.

    My blog: http://www.RyanVice.net/