SYSK 293: Business Rules – Easy, Flexible, Decoupled
From what I see, in this version, Microsoft Windows Workflow Foundation doesn’t allow you to author and use business rules without a link to an activity or a workflow… Also, the types of rules you can create are somewhat limited… After spending some time trying to fit WF into what I needed, I recalled the simplicity of the Microsoft ScriptControl object that allowed you to run VBScript or JavaScript code snippets, and even allowed to pass in parameters…
I wanted to have a mechanism where I can execute a .NET code snippet that was not previously compiled with the simplicity of the following statement:
ScriptEngine.Evaluate(codeBody, methodToInvoke, methodParameters);
So, I decided to create a class that can compile and run C# code on the fly… Imagine being able to create your business rules in C# (or VB.NET), maintain them in some secure but easy to edit place like database, and execute them when needed…
Here is my code (as always, use at your own risk, etc…):
using System;
using System.Collections.Generic;
using System.Text;
namespace YourCompany.YourProject
{
public class ScriptEngine
{
private static Dictionary<long, CachedCode> _cache = new Dictionary<long, CachedCode>();
public static object Evaluate(string code, string methodName, object[] parameters)
{
object snippetInstance = null;
System.Reflection.MethodInfo method = null;
// Did we already execute this code before?
long hashCode = code.GetHashCode();
if (_cache.ContainsKey(hashCode))
{
snippetInstance = _cache[hashCode].SnippetInstance;
method = _cache[hashCode].Method;
}
else
{
string codeToExecute =
"using System;" +
"public class CodeSnippetWrapper { " +
code +
"}";
Microsoft.CSharp.CSharpCodeProvider cp = new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.CompilerParameters p = new System.CodeDom.Compiler.CompilerParameters();
p.ReferencedAssemblies.Add("System.dll");
p.GenerateExecutable = false;
p.CompilerOptions = "/t:library";
p.GenerateInMemory = true;
System.CodeDom.Compiler.CompilerResults cr = cp.CompileAssemblyFromSource(p, new string[] { codeToExecute });
if (cr.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder(64);
foreach(System.CodeDom.Compiler.CompilerError e in cr.Errors)
{
sb.AppendLine(e.ToString());
}
throw new ApplicationException("Errors in rule " + methodName, new object[] { sb.ToString() });
}
System.Reflection.Assembly assembly = cr.CompiledAssembly;
snippetInstance = assembly.CreateInstance("CodeSnippetWrapper");
method = snippetInstance.GetType().GetMethod(methodName);
// Cache it for the future
_cache.Add(hashCode, new CachedCode(snippetInstance, method));
}
return method.Invoke(snippetInstance, parameters);
}
private class CachedCode
{
private object _snippetInstance = null;
private System.Reflection.MethodInfo _method = null;
public CachedCode(object snippetInstance, System.Reflection.MethodInfo method)
{
_snippetInstance = snippetInstance;
_method = method;
}
public object SnippetInstance
{
get { return _snippetInstance; }
}
public System.Reflection.MethodInfo Method
{
get { return _method; }
}
}
}
}
Comments
Anonymous
February 22, 2007
For scripting I prefer using LUA with LuaInterface for .NET integration. Is a much easier language for business rules scripting and is easily expandable, while the footprint is less than half a meg. Just a thought.Anonymous
February 22, 2007
Check out the Dynamic Code Activity on wf.netfx3.com What good is a business rule if you don't have some condition based on it, and what if you could declaratively state what happens based on the results when that business rule is evaluated? Welcome to WF.Anonymous
February 23, 2007
Hey Irena, Actually, you can do WF rules outside a workflow. I did a demo of that at the SOA Conference last fall ... http://blogs.msdn.com/richardbpi/archive/2006/10/07/Windows-Workflow-Rules-From-Outside-A-Workflow_2C00_-And-Other-Conference-Demos.aspx. Not a bad solution.Anonymous
February 23, 2007
Let me try to make it clear: as I understand it, to create rules in xaml using an authoring tool like one provided in Visual Studio Extensions for Windows Workflow Foundation, one has to first create an activity or a workflow. You could instanciate and run rules independently after that -- and there are samples on netfx3 that demonstrate that...Anonymous
March 07, 2007
Actually you don't need an activity to create rules nor do you have to run the rules against any activity. Any object will do, but you have to instanciate the RuleSetDialog yourself: RuleSetDialog ruleSetDialog = new RuleSetDialog(typeof(yourClass), null, null);