Wednesday, July 18, 2007

Rules, Rules, Rules !!

When we were all teenagers, we all hated rules. Do this, Don't do that. I was a fairly well behaved, albeit strange, teenager. So rules weren't a problem for me (well, except the one that I had to do all my chores before I could use the computer). But the kind of rules I'm talking about is something a bit different.


Enter Microsoft's .NET Framework 3.0 and the new technologies of Windows Worfklow (now called Workflow, or WF for short), Windows Communication Framework (WCF), and Windows Presentation Framework (WPF). For this post, I'm going to focus on Workflow and more precisely the Rules engine within Workflow. But before I go there, let's talk about what Workflow is.


Workflow is just that, the flow of work. It allows you to model a business process within your program and execute it. The age old example is requesting vacation time. In a large company, if you want vacation time, you have to request it and you can only have it if someone else from your department hasn't already requested that time off, if your manager approves it, etc. With Workflow, you can automated most of this process. Let's see how: You go to a website, select the start and end date for your vacation and the workflow begins it's job. It looks up the date range you have selected, it makes sure that you still have that many days available for vacation, checks the calendar for your department to make sure the days are available and notifies you via email if they are not (and terminates the workflow). Once it verifies the availability, it sends an email to your manager with all the necessary info. Within that email are two buttons: Approve and Decline. At this point the workflow goes to "sleep" and persisted to the database (to free up memory). Once your manager opens the email and clicks a button, the workflow is reloaded and picks up where it left off. If he clicked the decline button, you receive a "Sorry" email. If he clicked the "Approve" button then the calendar is updated with your vacation days and you receive a "Enjoy your vacation" email. Through this whole process the only human interaction was you making the request and your manager clicking a single button. All the complex work is performed by the workflow. This is wonderful, especially considering the development of the work flow is all done visually:



As you can see from this picture, you can define and visualize your workflow very easily and thanks to Visual Studio integration (download it here for Visual Studio 2005 or get the latest Beta of Visual Studio 2008 from here), you can easily and visually debug your workflow. This comes in really handy when dealing with logic snafus (when you start mixing ! and & and and (), things can get crazy).


A less known part of the Windows Workflow system is the Rules engine that is hidden beneath parts of certain activities (each part of a workflow is called an activity, they are the colored boxes in the picture). Anytime you can set a condition and have the choice of using a "declarative condition", you are using Rules.



What rules come down to is simply a CodeDOM XML document that gets parsed and converted into code that runs against the workflow allowing you to define complex conditions that take into account the whole workflow and not just the immediate state. The rules can be stored seperate from the workflow itself (in an XML file, database, come from a web service, wherever you want to put them basically), allowing you to change the logic without having to recompile the workflow. (For more on CodeDOM go here).


Editing the rules within Visual Studio is quite easy thanks to the built in Rules Editor that comes complete with IntelliSense (though a dumbed down version compared to the main code editor).

That's all fine and great if you are using workflows. But what if you want to use it seperate from the workflows? Well, that's actually quite easy. It really comes down to only 4-5 classes that you have to deal with and instead of using the Workflow as the target object, you can use whatever object you want as the root.

Let me demonstrate. Assume we have a CodeDOM document defining a ruleset (I'll show you later how to generate said document), the following code will convert it back into a RuleSet:




private RuleSet DeserializeRuleSet(string ruleSetXmlDefinition)
{
if (!String.IsNullOrEmpty(ruleSetXmlDefinition))
{
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
StringReader stringReader = new StringReader(ruleSetXmlDefinition);
XmlTextReader reader = new XmlTextReader(stringReader);
return serializer.Deserialize(reader) as RuleSet;
}
else
{
return null;
}
}


Once you deserialize the document (and because that method simply takes a string, the source can be from anywhere), you have to run the RuleSet, that is done with the following block of code:





  RuleValidation validation = new RuleValidation(root.GetType(), null);
  RuleExecution execution = new RuleExecution(validation, root);
  ruleSet.Execute(execution);

root is the object against which to run the RuleSet. Within the Ruleset, you basically specify a boolean statement (basically the "If" part of a If/Else statement) and what to do if it is true and what to do if it is false. You can specify multiple sets of If/Else rules within a single CodeDom document. All of them will be run against your root object.



Now, I know most of you who are programmers are saying "Great, show me the code." Click Here to go to the page to download the code. This is the ExternalRuleSet Demo project that first taught me how to use RuleSets. What!? You actually thought I figured this out on my own? Unfortunately, no. My thanks goes to Matt Winkler who wrote the example. Matt is the "technical evangelist" for Windows Workflow.



Ok, back to the code. Basically, there are 4 projects in the solution that you downloaded. The first ExternalRuleSet library contains two classes: RuleSetInfo (used to hold the name and version of the RuleSet you want to load from the database as you can version the rules) and RuleSetData (which holds the data loaded from the database and contains the code to deserialize the XML Data back into a RuleSet). The second library contains the RuleSetService. This class is responsible for loading the RuleSetData from the database and is used within the Workflow Engine to provide a RuleSet service to the Engine (if you want to use it that way). The third project is the PolicyActivities project, that provides you with an activity that you can place on your workflow to run the RuleSet against the workflow. But I basically stole the code for running workflows out of here and put it in my own project. The final project is the most important project as it is actually the rules editor. That project is called .... RuleSetTool. It is the RuleSetTool that generates and stores the CodeDOM XML Document within the database.



So go ahead, take a look at the code and see all the cool things you can do with Rules!!

1 comment:

Brandon said...

Very informative. thanks!