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;




                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.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)





                    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; }