WF Rules: Unleashing The Rule Engine Within .NET

October 18, 2010

I have written previously about WF Rules, the rule engine that ships in .NET. As I have described, this rule engine is bundled in .NET versions 3.0 and higher, and is included in the default installation of Windows Vista and Windows 7. (If you are using .NET 4.0, you need the Extended / Full install – the WF Rules assemblies are not in the Client install.)

Getting Access To WF Rules
The average rule author who is looking to try out WF Rules will ask where to start. At they point, they may become lost in the sea of WF documentation or find that they are told to use Visual Studio, which they may not even have installed. It is indeed the case, that WF Rules is typically used as part of Windows Workflow Foundation, and the rules are typically authored within Visual Studio. However, WF Rules can also be used without Visual Studio or Workflow Foundation if one is willing to read through the documentation, download some samples and write a bit code.

A Simple Example
Inspired by a co-worker, I have put together this quick example to lower the barrier to entry a bit. This is a very bare-bones example in order to highlight the rule-specific code that is needed to utilize WF Rules without Visual Studio or Workflow Foundation. So, the code will not feature command-line arguments, a mutable file name, factoring for re-use, etc. (If you are reading this, you most likely already know how to do those things in C#.) The emphasis here is upon demonstrating the scenario with the minimum amount of code. You should be able to paste these three code snippets into three files and have a working example.

The Target Type
In order to author rules, we require a target type to write the rules against. Let’s start with a simple data class:

using System;

class Person
{
  double age;
  public double Age { 
    get
    {
      return age;
    }
    set
    {
      age = value; 
    }
  }
}

For this example, I placed this code in a file named Person.cs. You may choose to place this type within the same file as the other code below. As I said, this example is geared for simplicity.

The RuleSetDialog
Now, let’s write some short code that will instantiate the RuleSetDialog and allow us to author a rule. This code needs to do three things:

  1. Open an existing or create a new .rules file – the WorkflowMarkupSerializer is used if we load an existing RuleSet
  2. Instantiate the RuleSetDialog, while supplying the target type
  3. Save the .rules file if the rules have been updated – using the WorkflowMarkupSerializer

Here is a minimal program to do this:

using System;
using System.IO;
using System.Windows.Forms;
using System.Workflow.Activities.Rules;
using System.Workflow.Activities.Rules.Design;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Xml;

class Program
{
  static string filename = "Test.rules";

  static void Main()
  {
    RuleSet ruleset = null;
	
    // Obtain or create ruleset
    if (File.Exists(filename))
    {
      // load file
      ruleset = Load(filename);
    }
    else
    {
      ruleset = new RuleSet();
    }

    RuleSetDialog dialog = new RuleSetDialog(typeof(Person), null, ruleset);
    DialogResult result = dialog.ShowDialog();

    if (result == DialogResult.OK)
    {
      // save the file
      Save(filename, dialog.RuleSet);
    }
  }

   static RuleSet Load(string filename)
  {
    XmlTextReader reader = new XmlTextReader(filename);
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    object results = serializer.Deserialize(reader);
    RuleSet ruleset = (RuleSet)results;

    if (ruleset == null)
    {
       Console.WriteLine("The rules file " + filename + " does not appear to contain a valid ruleset.");		
    }
   return ruleset;
  }

  static void Save(string filename, RuleSet ruleset)
  {     
    XmlTextWriter writer = new XmlTextWriter(filename, null);
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    serializer.Serialize(writer, ruleset);
    Console.WriteLine("Wrote rules file: " + filename);
  }
}

Authoring A Simple Rule
You will need to save each of these files before you can compile them – for example, I named them Person.cs and RuleEditor.cs.

Now we need to compile these files. You will typically find the C# compiler wherever your .NET installation is, for example:
C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe

Let me emphasize this – you don’t need Visual Studio for this example. If you have .NET on your machine, you should have the C# compiler already available.

If you saved the files as Person.cs and RuleEditor.cs and pass them to the compiler at the same time, you should end up with RuleEditor.exe – which we can then use to author a rule against a Person. Depending upon your environment settings, you may need to provide the following reference assemblies to the compiler at the same time: System.Workflow.Activities.dll, System.Workflow.ComponentModel.dll, and System.Workflow.Runtime.dll.

Now you should be able to execute RuleEditor.exe and author a rule such as this (click the picture to see full details):
Creating a simple rule in the rule editor dialog

Firing The Rules
Once we have our example rule authored, we need a simple program to load the ruleset and call the rule engine so we can fire the rules. (Note that the code here for loading the ruleset is the same as above.)

using System;
using System.IO;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Xml;

class Program
{
  static string filename = "Test.rules";

  static void Main()
  {
    RuleSet ruleset = null;

    Person person = new Person();
    person.Age = 70;
		
    if (File.Exists(filename))
    {
      // load file
      ruleset = Load(filename);
    }
	
    if (ruleset != null)
    {
      RuleValidation validation = new RuleValidation(person.GetType(), null);
      RuleExecution engine = new RuleExecution(validation, person);
      ruleset.Execute(engine);
    }
  }

  static RuleSet Load(string filename)
  {
    XmlTextReader reader = new XmlTextReader(filename);
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    object results = serializer.Deserialize(reader);
    RuleSet ruleset = (RuleSet)results;

    if (ruleset == null)
    {
      Console.WriteLine("The rules file " + filename + " does not appear to contain a valid ruleset.");		
    }
    return ruleset;
  }
}

This program should build much the same as the previous program. You will need to include the Person class again. In a real application, we would factor the business objects into a shared library.

Closing
I hope that this bit of code has demonstrated how readily WF Rules can be used by itself. I find it neat to see a rule engine included in a default OS installation.

Resources


Action Videogames Train Your Brain For Decision-Making

September 21, 2010

Researcher Daphne Bavelier is back with more videogame research. Once again, the study used The Sims 2, Call Of Duty 2, and Unreal Tournament.

The results of this study showed that those who played the action games made quicker decisions:

“In the problem-solving exercise, the action-game players made decisions 25 percent faster than the strategy group, while answering the same number of questions correctly.”


Chernoff Face Tutorial on Flowing Data

September 20, 2010

If you’ve read Blindsight, then you have come across Chernoff faces.

I recently spotted a tutorial on Flowing Data for using Chernoff faces with R.


How Language Shapes How We Think

September 17, 2010

The New York Times has a fascinating article on how the language we speak may or may not shape the way we think. The title is “Does Your Language Shape How You Think?” and it is written by Guy Deutscher.

This is clearly a topic that has been plagued by pseudo-science over the decades, and we are only now beginning to get real data. Consider the Australian aboriginal language Guugu Yimithirr, in which the position of objects relies on cardinal directions such as “north” or “south”. They do not make use of such terms as “in front of” or “behind”. This is well illustrated as follows:

“One way of understanding this is to imagine that you are traveling with a speaker of such a language and staying in a large chain-style hotel, with corridor upon corridor of identical-looking doors. Your friend is staying in the room opposite yours, and when you go into his room, you’ll see an exact replica of yours: the same bathroom door on the left, the same mirrored wardrobe on the right, the same main room with the same bed on the left, the same curtains drawn behind it, the same desk next to the wall on the right, the same television set on the left corner of the desk and the same telephone on the right. In short, you have seen the same room twice. But when your friend comes into your room, he will see something quite different from this, because everything is reversed north-side-south. In his room the bed was in the north, while in yours it is in the south; the telephone that in his room was in the west is now in the east, and so on. So while you will see and remember the same room twice, a speaker of a geographic language will see and remember two different rooms.”


Data Dangers Redux

September 16, 2010

Recent bit from the New York Times about burglars picking houses based on Facebook status updates. Not surprising at all. Does remember to namecheck PleaseRobMe.com.

See also Tom Scott’s project that datamines public phone numbers from Facebook.


Your Brain On Computers

September 15, 2010

The New York Times has had a nice series of articles recently on the topic of brains and computers entitled “Your Brain On Computers”.


The Matthew Effect Shows Up in ADHD Diagnosis

September 14, 2010

It seems that the Matthew Effect shows up in the diagnosis of ADHD.

If you have read Outliers, this shouldn’t come as a surprise.


Every Rubik’s Cube Position Solvable In 20 Moves Or Less Proven

September 13, 2010

It is always interesting to see computing power used to completely solve a game such as Connect Four or Checkers.

Now, it has been proven that every position of a Rubik’s Cube can be solved in 20 moves or less.

“It took fifteen years after the introduction of the Cube to find the first position that provably requires twenty moves to solve; it is appropriate that fifteen years after that, we prove that twenty moves suffice for all positions.”


Games As A Killer App For AI

August 2, 2010

It has been ten years to the day since John E. Laird and Michael van Lent published their paper “Human-level AI’s Killer Application: Interactive Computer Games”. In ten years, what has and hasn’t changed?

(Direct link to PDF at Laird’s homepage)


Microsoft Rule Engine Survey

June 1, 2010

Are you interested in helping to shape Microsoft’s future rules products?

Microsoft is running a survey on rule engines in general, and its own rule products (WF Rules, MS BRE) in particular through the end of this week – June 4. (I would have blogged it yesterday, but was off due to holiday.)

The survey should take approximately 5 minutes to complete. If you have used the WF Rules product, you will get a few additional questions about your usage of the features. If you only use non-Microsoft rule engines, your participation is welcome as well.

Your input is appreciated.

Microsoft Rule Engine survey