• mwinkle.blog

    WF and BizTalk

    • 1 Comments

    Before joining Microsoft, I did spend a fair amount of time in the BizTalk world, and to this day, it remains one of the most common source of questions I am asked when presenting on WF.

    Paul showed off some cool stuff at TechEd, and yesterday released the code to enable a pretty interesting pattern where processes can be modeled in WF and then an orchestration can be created from the workflow to handle the messaging.  This gives you the flexible process modeling in WF and then rely on  BizTalk to handle all those messy real world details like transforming messages in the send port, communicating via the built in adapters, and handling retries. 

    This is a cool project that let's you use both technologies together today.  Check it out and give feedback at the connect site!

  • mwinkle.blog

    Pageflow Sample Update

    • 2 Comments

    Updated to version 1.1

    Changes

    • Corrected the install to display the EULA at a more opportune time (thanks to this comment)
    • Updated to fix the exception being thrown at the completion of a workflow
      • NavigationManager.cs
      • AspUserInput.cs
      • WebHostingModule.cs

    To install this, download the bits (same location), uninstall the existing version and install this version.

    Other Setup Notes

    I got a few pieces of feedback on the setup to get things working, here are some hints to get up and running:

    • If you extract the samples.zip file in the install directory (Program Files\Windows Workflow Foundation Samples\...) they may be marked as read-only.  Mark the whole directory as non-read-only (so you can write) and then you will be able to compile successfully.
    • To run the sample, you need to set up a persistence database, this will be used to store the state of the workflow while we are not interacting with it
      • Then go into the App.config or web.config and find the ConnectionString settings and update it to point to the correct database.  On most default VS installs, you can point at localhost\sqlexpress, but it can certainly be any sql install.

    Other Notes

    For the folks using WCSF, Glenn has a good summary that fills in some of the story on the WCSF side, and sneaks an Eminem reference into the title :-)

  • mwinkle.blog

    Implementing the N of M Pattern in WF

    • 11 Comments

    The second in my series of alternate execution patterns (part 1)

    I recently worked with a customer who was implementing what I would call a "basic" human workflow system. It tracked approvals, rejections and managed things as they moved through a customizable process. It's easy to build workflows like this with an Approval activity, but they wanted to implement a pattern that's not directly supported out of the box. This pattern, which I have taken to calling "n of m", is also referred to as a "Canceling partial join for multiple instances" in the van der Aalst taxonomy.

    The basic description of this pattern is that we start m concurrent actions, and when some subset of those, n, complete, we can move on in our process and cancel the other concurrent actions. A common scenario for this is where I want to send a document for approval to 5 people, and when 3 of them have approved it, I can move on. This comes up frequently in human or task-based workflows. There are a couple of "business" questions which have to be answered as well, the implementation can support any set of answers for this:

    • What happens if an individual rejects? Does this stop the whole group from completing, or is it simply noted as a "no" vote?
    • How should delegation be handled? Some business want this to break out from the approval process at this point.

    The first approach the customer took was to use the ConditionedActivityGroup (CAG). The CAG is probably one of the most sophisticated out of the box activities that we ship in WF today, and it does give you a lot of control. It also gives you the ability to set the Until condition which would allow us to specify the condition that the CAG could complete, and the others would be cancelled (see Using ConditionedActivityGroup)

    ConditionedActivityGroup

    What are pros and cons of this approach:

    Pros

    • Out of the box activity, take it and go
    • Focus on approval activity
    • Possibly execute same branch multiple times

    Cons

    • Rules get complex ( what happens if the individual rejections causes everything to stop)
    • I need to repeat the same activity multiple times (especially in this case, it's an approval, we know what activity needs to be in the loop)
    • I can't control what else a developer may put in the CAG
    • We may want to execute on some set of approvers that we don't know at design time, imagine an application where one of the steps is defining the list of approvers for the next step. The CAG would make that kind of thing tricky.

    This led us to the decision to create a composite activity that would model this pattern of execution. Here are the steps we went through:

    Build the Approval activity

    The first thing we needed was the approval activity. Since we know this is going to eventually have some complex logic, we decided to take the basic approach of inheriting from SequenceActivity and composing our approval activity out of other activities (sending email, waiting on notification, handling timeouts, etc.). We quickly mocked up this activity to have an "Approver" property, a property for a timeout (which will go away in the real version, but is useful to put some delays into the process. We also added some code activities which Console.WriteLine 'd some information out so we knew which one was executing. We can come back to this later and make it arbitrarily complex. We also added the cancel handler so that we can catch when this activity is canceled (and send out a disregard email, clean up the task list ,etc). Implementing ICompensatableActivity may also be a good idea so that we can play around with compensation if we want to (note, that we will only compensate the closed activities, not the ones marked as canceled).

    Properties of the Approval Activity

    Placing the Approval Activity inside our NofM activity.

    What does the execution pattern look like?

    Now that we have our approval activity, we need to determine how this new activity is going to execute. This will be the guide that we use to implement the execution behavior. There are a couple of steps this will follow

    1. Schedule the approval's to occur in parallel, one per each approver submitted as one of the properties
    2. Wait for each of those to finish.
    3. When one finishes, check to see if the condition to move onward is satisfied (in this case, we increment a counter towards a "number of approvers required" variable.
    4. If we have not met the criteria, we keep on going. [we'll come back to this, as we'll need to figure out what to do if this is the last one and we still haven't met all of the criteria.]
    5. If we have met the criteria, we need to cancel the other running activities (they don't need to make a decision any more).
    6. Implement the easy part of this (scheduling the approvals to occur in parallel)

    I say this is the easy part as this is documented in a number of places, including Bob and Dharma's book. The only trickery occurring here is that we need to clone the template activity, that is the approval activity that we placed inside this activity before we started working on it. This is a topic discussed in Nate's now defunct blog.

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            // here's what we need to do.
            // 1.> Schedule these for execution, subscribe to when they are complete
            // 2.> When one completes, check if rejection, if so, barf
            // 3.> If approve, increment the approval counter and compare to above
            // 4.> If reroute, cancel the currently executing branches.
            ActivityExecutionContextManager aecm = executionContext.ExecutionContextManager;
            int i = 1;
            foreach (string approver in Approvers)
            {
                // this will start each one up.
                ActivityExecutionContext newContext = aecm.CreateExecutionContext(this.Activities[0]);
                GetApproval ga = newContext.Activity as GetApproval;
                ga.AssignedTo = approver;
                // this is just here so we can get some delay and "long running ness" to the
                // demo
                ga.MyProperty = new TimeSpan(0, 0, 3 * i);
                i++;
                // I'm interested in what happens when this guy closes.
                newContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
                newContext.ExecuteActivity(newContext.Activity);
            }
            return ActivityExecutionStatus.Executing;
        }
    

    Code in the execute method

    One thing that we're doing here is RegisterForStatusChange() This is a friendly little method that will allow me to register for a status change event (thus it is very well named). This is a property of Activity, and I can register for different activity events, like Activity.ClosedEvent or Activity.CancelingEvent. On my NofM activity, I implment IActivityEventListener of type ActivityExecutionStatusChangedEvent (check out this article as to what that does and why). This causes me to implement OnEvent which since it comes from a generic interface is now strongly typed to accept the right type of event arguments in. That's always a neat trick that causes me to be thankful for generics. That's going to lead us to the next part.

    Implement what happens when one of the activities complete

    Now we're getting to the fun part of how we handle what happens when one of these approval activities return. For the sake of keeping this somewhat brief, I'm going to work off the assumption that a rejection does not adversely affect the outcome, it is simply one less person who will vote for approval. We can certainly get more sophisticated, but that is not the point of this post! ActivityExecutionStatusChangedEventArgs has a very nice Activity property which will return the Activity which is the one that caused the event. This let's us find out what happened, what the decision was, who it was assigned to, etc. I'm going to start by putting the code for my method in here and then we'll walk through the different pieces and parts.

    public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
    {
        ActivityExecutionContext context = sender as ActivityExecutionContext;
        // I don't need to listen any more
        e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
        numProcessed++;
        GetApproval ga = e.Activity as GetApproval;
        Console.WriteLine("Now we have gotten the result from {0} with result {1}", ga.AssignedTo, ga.Result.ToString());
        // here's where we can have some additional reasoning about why we quit
        // this is where all the "rejected cancels everyone" logic could live.
        if (ga.Result == TypeOfResult.Approved)
            numApproved++;
        // close out the activity
        context.ExecutionContextManager.CompleteExecutionContext(context.ExecutionContextManager.GetExecutionContext(e.Activity));
        if (!approvalsCompleted  && (numApproved >= NumRequired))
        {
            // we are done!, we only need to cancel all executing activities once
            approvalsCompleted = true;
            foreach (Activity a in this.GetDynamicActivities(this.EnabledActivities[0]))
                if (a.ExecutionStatus == ActivityExecutionStatus.Executing)
                    context.ExecutionContextManager.GetExecutionContext(a).CancelActivity(a);
        }
        // are we really done with everything? we have to check so that all of the 
        // canceling activities have finished cancelling
        if (numProcessed == numRequested)
            context.CloseActivity();  
    }
    

    Code from "OnEvent"

    The steps here, in English

    • UnregisterForStatusChange - we're done listening.
    • Increment the number of activities which have closed (this will be used to figure out if we are done)
    • Write out to the console for the sake of sanity
    • If we've been approved, increment the counter tracking how many approvals we have
    • Use the ExecutionContextManager to CompleteExecutionContext, this marks the execution context we created for the activity done.
    • Now let's check if we have the right number of approvals, if we do, mark a flag so we know we're done worrying about approves and rejects and then proceed to cancel the activities. CancelActivity. CancelActivity schedules the cancellation, it is possible that this is not a synchronous thing (we can go idle waiting for a cancellation confirmation, for instance.
    • Then we check if all of the activities have closed. What will happen once the activities are scheduled for cancellation is that each one will eventually cancel and then close. This will cause the event to be raised and we step through the above pieces again. Once every activity is done, we finally close out the activity itself.

    Using it

    I placed the activity in a workflow, configured it with five approvers and set it for two to be required to move on. I also placed a code activity outputting "Ahhh, I'm done". I also put a Throw activity in there to raise an exception and cause compensation to occur to illustrate that only the two that completed are compensated for.

    So, what did we do?

    • Create a custom composite activity with the execution logic to implement an n-of-m pattern
    • Saw how we can use IEventActivityListener in order to handle events raised by our child activities
    • Saw how to handle potentially long running cancellation logic, and how to cancel running activities in general.
    • Saw how compensation only occurs for activities that have completed successfully

    Extensions to this idea:

    • More sophisticated rules surrounding the approval (if a VP or two GM's say no, we must stop)
    • Non binary choices (interesting for scoring scenarios, if the average score gets above 95%, regardless of how many approvers remaining, we move on)
    • Create a designer to visualize this, especially when displayed in the workflow monitor to track it
    • Validation (don't let me specify 7 approvals required, and only 3 people)
  • mwinkle.blog

    Pageflow questions: "What about WCSF / Acropolis / Codename 'foo'"?

    • 1 Comments

    So, I got a little bit of feedback from my initial post.  First, thanks, it's great to see all of the interest in the technology.  I want to use this as the place to answer common questions that arise about the sample. 

    Here's one that I got internally as well as externally(here, here )

    What about WCSF and Acropolis?  Does this change how we think about the problem today? 

    The short answers are "they are still here", "no".

    WCSF 

    There are a lot of people who are using the Web Client Software Factory.  It is definitely something you should check out, it is a great toolkit to build composite web applications.  Part of what it does, among many other things, is the Pageflow Application Block designed to model navigation.   This is what most people are wondering about when they first hear about the pageflow sample we released.  Don't they do the same thing?  From a functional level, yes, they both provide a nice abstraction to model flow through an application.  This is a sample usage of WF to solve a similar problem in a little bit of a different way.  The model inside the WCSF is extensible, allowing a different provider of pageflow information, so it is probably even possible to put this pageflow sample inside of the WCSF, I have yet to give that a try.

    At a deeper level, there are some differences that stem from the implementation of the Pageflow Application Block as a state machine, which I will get into in my next post.

    Acropolis

    Acropolis, announced at TechEd last week, is still early on in its lifecycle, as part of the ".NET Client Futures".  I haven't spent a lot of time looking at it yet, but it is something else which will have a way to model the flow within an application, in this case between WPF forms. 

    Conclusion

    From a support perspective, it's important to note that this sample is unsupported (save for myself and a few others) as opposed to Acropolis and WCSF which have teams working on them.

    It is important to note that both WCSF and Acropolis aim to solve a much larger problem than simple UI navigation.  In that sense, in no way does the pageflow sample released represent a wholesale replacement of either of them.  The sample that we released aims to illustrate a way to use WF to solve the problem of UI navigation.  The important thing to take away from this is that it can be incredibly valuable to model the flow through one's application using a technology which allows separation from the UI.  This makes our UI more loosely coupled with the rest of our application, and increases the agility to react to changes in process / data required / need to track infomation. 

    Also, even if you don't want to use this for pageflow, tune in, because there are some pretty valuable things that any WF developer can learn by taking a look at this sample.  I will continue to discuss those as well.

  • mwinkle.blog

    Pageflow Questions: Why not a state machine?

    • 1 Comments

    Here's a comment from my initial post introducing the pageflow sample from wleong:

    NavigatorWorkflow looks like a state machine to me.  Why create a new workflow type?

    Tuesday, June 12, 2007 3:44 AM by wleong

    This is a good question.  There a couple of reasons why we create our own workflow type:

    • To more accurately model a process
    • Enable different execution semantics
    • Make development faster by focusing on the model, not the implementation details.

    For a little more background on the problem, see my previous post on "Different Execution Patterns for WF (or, Going beyond Sequential and State Machine)" that talks in a little more depth about the trouble one can encounter by only think about the two out of the box models.

    For this problem, in particular, all of the reasons are relevant.

    Accurately modeling a process

    It is very natural to think of UI navigation as a series of places we can be, and a set of transitions from any one of those places to another.  That's what the navigator workflow models.  There is a subtle difference from a state machine that plays to point 3 here.  This model allows me to not worry about putting an IEventActivity at the top of a state, then making some decision and then setting a new state.  We abstract away from defining the events, that's taken care of for us.  This lets us model the process naturally.  In a state machine, one could argue that modeling pageflow with transitions has me place one event and then have an IfElse activity that lets me decide which state to transition to.  This adds mental overhead to the model, moving me much closer to the implementation details (again, point 3).

    Enable Different Execution Semantics

    This was the primary reason I wrote the original article, my customer was doing some very unnatural acts in order to model their process in a sequential workflow.  In the case of UI navigation, we have the ability to be in multiple interactions at the same time.  The WF state machine has the (very natural) restriction that we can only be in one state at a given time (although there are certainly other state machine models that do not have that restriction). The pageflow sample allows you to be in multiple interactions at the same time, so think about filling out a mortgage application, I can be in the midst of many minor sub processes that all roll up into the larger application process, and I can jump from filling out my salary history to the details of the property I am buying by simply clicking on a tab at the top of the page.

    Make development faster by focusing on the model, not the implementation details.

    If we decide to use a state machine, we are coupling our model to the implementation and execution details of the state machine, which will cause us to do things that we don't need to do for this application.  The WF state machine is generic, any state can receive n different events and react to each on differently.  In pageflow, we know there is only one event, "GoForward" and then we have a set of rules to operate on that to determine where we transition to.  By spending the time to create our own root activity, we remove the burden of the implementation details from the workflow developer, allowing them to focus on the details of their process, not the configuration of a given activity.

  • mwinkle.blog

    Introducing the Pageflow Sample

    • 40 Comments

      Most people think of workflows as a tool to represent and automate back-end business processes. Back-end business processes normally require some user interaction but their main purpose is not to drive the user experience or manage the UI. However, there is a growing type of application that leverages workflow as a tool to drive the user interaction and drive the user experience of an interactive process. This type of technology is called page flow.

      Last year at TechEd, we showed off some bits we had been working on internally that were designed to make that possible, the ability to model the user interaction of an application using workflow. This approach provides developers the ability to continue managing the complexity of their application in a structure and scalable manner. It turned out that the code we showed at TechEd wasn't going to end up in any of the product releases, so the dev team requested permission to release that code as a sample of how one can implement a generic navigation framework using WF that can support multiple UI technologies (i.e. ASP.NET and WPF).  This year, I just finished giving a talk showing this off and talking about how it will be available today!

      Thanks go to Shelly Guo, the developer and Israel Hilerio, the PM who had worked on this feature, and to Jon Flanders for providing packaging and quality control

      Now for the good stuff, download the bits from here!

      Navigate to setup.exe and run the setup, this will copy the sample projects and the source code for the sample, as well as some new visual studio project templates.

      Now, let's open up a sample project, so navigate to the samples directory and open the ASPWorkflow sample, this will show off both an ASP.NET Front end as well as a WPF Controller (you can actually use the two together). Let's get to the good stuff right away, and open up the workflow file.

      Wow… what's going on here? It kind of looks like a state machine, but not really. What has been done here is to create a new base workflow type. Things like SequentialWorkflow and StateMachineWorkflow aren't the only ways to write workflows, they are just two common patterns of execution. A NavigatorWorkflow type has been created (and you can inspect the source and the architecture document to see what this does) and a WorkflowDesigner has been created for it as well (again, this source is available as a guide for those of you who are creating your own workflow types).

      Each of the activities you see on the diagram above is an InteractionActivity, representing the interaction between the user (via the UI technology of their choosing) and the process. A nice model is to think of the InteractionActivity as mapping to a page within a UI. The output property is the information that is sent to that page (a list of orders or addresses to display) and the input is the information that is received from the page when the user clicks "submit". The InteractionActivity is a composite activity, allowing one to place other activities within the activity to be executed when input is received. The interesting property of the InteractionActivity is the Transitions collection. By selecting this and opening its designer, we are presented with the following dialog:

      This allows us to specify n-transitions from this InteractionActivity or "page" to other InteractionActivities. And we can specify this via a WF activity condition. This way, we could forward orders greater than $1000 to a credit verification process, or orders containing fragile goods through a process to obtain insurance from a shipper. What's cool about this, my page does not know about that process, it just says "GoForward" and my process defines what comes next. This de-couples the pages from the logic of your process.

      We then need to wire things up in config:

      <configSections>
      <section name="NavigationManagerSettings" 
      type="Microsoft.Samples.Workflow.UI.NavigationManagerConfigSection, Microsoft.Samples.Workflow.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=40B940EB90393A19"/>
      <section name="AspNavigationSettings" 
      type="Microsoft.Samples.Workflow.UI.Asp.AspNavigationConfigSection, Microsoft.Samples.Workflow.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=40B940EB90393A19"/>
      </configSections>
      
      

      <NavigationManagerSettings StartOnDemand="false">
        <Workflow mode="Compiled" value="ASPUIWorkflow.Workflow1, ASPUIWorkflow"/>
        <!--<Workflow mode="XOML" value="WebSite/XAMLWorkflow.xoml" rulesFile="WebSite/XAMLWorkflow.rules" />-->
        <Services>
          <add type="System.Workflow.Runtime.Hosting.DefaultWorkflowCommitWorkBatchService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
          <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" ConnectionString="Initial Catalog=WorkflowStore;Data Source=localhost;Integrated Security=SSPI;" UnloadOnIdle="true"/>
        </Services>
      </NavigationManagerSettings>
      <AspNavigationSettings>
        <PageMappings>
          <add bookmark="Page1" location="/WebSite/Default.aspx"/>
          <add bookmark="Page2" location="/WebSite/Page2.aspx"/>
          <add bookmark="Page3" location="/WebSite/Page3.aspx"/>
          <add bookmark="Page4" location="/WebSite/Page4.aspx"/>
          <add bookmark="Page5" location="/WebSite/Page5.aspx"/>
          <add bookmark="LastPage" location="/WebSite/LastPage.aspx"/>
        </PageMappings>
        <ExceptionMappings>
          <add type="Microsoft.Samples.Workflow.UI.WorkflowNotFoundException" location="/WebSite/ErrorPage.aspx"/>
          <add type="Microsoft.Samples.Workflow.UI.WorkflowCanceledException" location="/WebSite/ErrorPage.aspx"/>
          <add type="System.ArgumentException" location="/WebSite/ErrorPage.aspx"/>
          <add type="System.Security.SecurityException" location="/WebSite/ErrorPage.aspx"/>
        </ExceptionMappings>
      </AspNavigationSettings>
      
      

       

      Finally, let's look inside an ASP.NET page and see what we need to do to interact with the process:

      AspNetUserInput.GoForward("Submit", userInfo, this.User);

      This code is specifying the action and is submitting a userInfo object (containing various information gathered from the page) to the InteractionActivity (in this case, it submits to the Page2 InteractionActivity). If we look at what we've configured as the Input for this InteractionActivity, we see the following, which we can then refer to in the transition rules in order to make decisions about where to go next:

      Plenty of other stuff we could talk about here, support for back button, persistence, etc and I could continue to ramble on about this in another record-length blog post, but I will stop here for now. I will continue to blog about this, look forward to hearing any and all types of feedback, and what you'd be interested in seeing in this. Moving forward, there aren't any formal plans around this, but if there is enough interest in the community, we could get it created as a project on codeplex. If that sounds intriguing either contact me through this blog, leave a comment so that I can gauge the interest in such a scenario.

      Go, grab the bits!  And, if you have feedback, please contact me.

  • mwinkle.blog

    Down In Orlando

    • 0 Comments

    David and I arrived in Orlando yesterday morning via the redeye for TechEd 2007. We're settled into the Port Orleans French Quarter, and will be heading on over to the conference center later today.  Once we get all checked in, I'll post some info on the talks I'll be giving, and the talks that I wouldn't want to miss.  For now, I'm out to enjoy the non-Seattle-like weather and adjust to the time change. 

  • mwinkle.blog

    HELP WANTED

    • 0 Comments

    My boss, James, has a post on his blog about two positions that are open on our team.  One focuses on Orcas evangelism, while the other is for IIS7.  Our team does a ton of cool stuff, and if you're interested, certainly drop James a line.  If you want to create, deliver, and scale your passion for .net (or IIS) to the world, give it a look!

Page 1 of 1 (8 items)