Sunday, December 10, 2006

Windows Workflow - Design - Best Practice?

The purpose of this post is to define what seems to be a useful approach when designing workflows that contain activities that you may want to reuse, that use some common values. Essentially, I needed something like a "Session" variable within my workflow. If I figure out a better way, I will blog about it, until then...

Essentially, I've been working on a workflow that contains a number of activities that I may want re-use. In order to accomplish this, it is important to develop each activity so that it is autonomous.

The problem that I have run into is, I essentially need something like the "Session" variable from ASP.NET (documentation). Because of the design of the workflow, and the desire to reuse these activities, there are some values that I need to retrieve after an activity is run, through a code activity and use that value in 1 or more activities down the road. Personally, I couldn't find any built in functionality into Windows Worflow to allow you to do this. If someone knows of a better way, please post a comment. For now, you can download the source code that will be used in this post here.

In order to display how I have accomplished this "Session" variable, let's extend the workflow from 11-21-2006 to make our workflow look like the following:

Essentially, the purpose of "myActivity" is simply to set the first/last name information. The purpose of the "codeActivity1" is to create an e-mail address based upon the first and last name entered into myActivity. Finally, "myOtherActivity" is responsible for displaying the user's newly generated e-mail address.

Essentially, it will make the most sense to review the code knowing that:

  • We are trying to create "Session" type functionality
  • There maybe a better way to do this particular example, however, it's purpose is to display the "Session" type functionality.

Now to walk through the code. The first step is to setup a "Session" variable within the workflow. This step is implemented by inserting the following code into the "MyWorkflow.cs" file.

// Contains the information to be used throughout the workflow
private Dictionary<string, object> session = new Dictionary<string, object>();
public Dictionary<string, object> Session
  get { return session; }
  set { session = value; }

Next, the "codeActivity1" "ExecuteCode" method is set to call "SetEmailAddress". The "SetEmailAddress" method is defined within "MyWorkflow.cs" and looks like the following:

public void SetEmailAddress(object sender, EventArgs e)
  // Pretend that this value is retrieved from some external
  // data source (database, registry, web service, etc)
  string emailAddress = firstName.ToLower() + "." +
    lastName.ToLower() + "";
  session["EmailAddress"] = emailAddress;

After implementing the preceeding code, the magic happens within the "MyOtherActivity.cs" file. A new method called "HydrateProperties" has been added. This method is called right at the start of the "Execute" method. "HydrateProperties" is defined as follows:

private void HydrateProperties()
  // Retrieve the root activity (the actual workflow activity)
  Activity workflowActivity = this;
  while (workflowActivity.Parent != null)
    workflowActivity = workflowActivity.Parent;
  MyWorkflow myWorkflow = (MyWorkflow)(workflowActivity);

  // Based upon your precedence needs, you may want to only set a property from
  // the session if it has not been set from the workflow designer. If you want to set
  // the property no matter what, just remove the "if" statement.
  if (EmailAddress.Trim().Length == 0)
    EmailAddress = Convert.ToString(myWorkflow.Session["EmailAddress"]);

That's it! I hope this helps and if you come across a similar situation. In addition, if you know of a more recommended approach, please post some info within the comments.

You can download the source code for this example here.

No comments: