<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://bloggingabout.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tag 'WF'</title><link>http://bloggingabout.net/search/SearchResults.aspx?a=1&amp;o=DateDescending&amp;tag=WF&amp;orTags=0</link><description>Search results matching tag 'WF'</description><dc:language>en-US</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Simple Rule Editor goes to BitBucket</title><link>http://bloggingabout.net/blogs/vagif/archive/2010/05/20/simple-rule-editor-goes-to-bitbucket.aspx</link><pubDate>Thu, 20 May 2010 08:09:39 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:483303</guid><dc:creator>VagifAbilov</dc:creator><description>&lt;p&gt;About a year ago I wrote a blog post where I described a &lt;a href="http://bloggingabout.net/blogs/vagif/archive/2009/04/13/wysiwyg-rule-editor-create-and-test-rules-for-any-net-type.aspx" target="_blank"&gt;simple WYSIWIG rule editor&lt;/a&gt; that can be used to manage rules applied using WF rule engine. After that I received a few responses with comments and questions about using WF rule engine in .NET applications. Apparently this technique was considered useful in various projects, and I even presented it on a &lt;a href="http://www.nnug.no/Avdelinger/Oslo/Moter/Brukergruppemote-10-mai-2010/" target="_blank"&gt;recent NNUG session&lt;/a&gt; in Oslo.&lt;/p&gt;  &lt;p&gt;Few days ago I received a mail from one developer who complained that my rule enging wrapper was unable to handle Nullable&amp;lt;T&amp;gt; types. I never invested enough time to make the wrapper handle such issues, the whole thing was more like a demonstration of a concept. However, since it is now used by others, I decided to have more solid approach to it and moved the project to BitBucket where it’s source can be obtained from &lt;a href="http://bitbucket.org/object/ruleeditor/overview" target="_blank"&gt;here&lt;/a&gt;. I also updated WF rule engine wrapper to correctly handle converstion to nullable types. This is a common problem. Strings can not be converted to a generic Nullable&amp;lt;T&amp;gt; type using Convert.ChangeType call. I had to modify RyleType.SetPropertyValue method that now looks like this:&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;public void SetPropertyValue(RuleObject ruleObject, int index, object value)
{
    object propertyValue;
    if (this.Properties[index].Type.IsEnum)
    {
        propertyValue = Enum.Parse(this.Properties[index].Type, value.ToString());
    }
    else if (this.Properties[index].Type.IsGenericType &amp;amp;&amp;amp; this.Properties[index].Type.GetGenericTypeDefinition().Equals(typeof(Nullable&amp;lt;&amp;gt;)))
    {
        System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(this.Properties[index].Type);
        propertyValue = System.Convert.ChangeType(value, nullableConverter.UnderlyingType);
    }
    else
    {
        propertyValue = Convert.ChangeType(value, this.Properties[index].Type);
    }
    this.Properties[index].PropertyInfo.SetValue(ruleObject.PropertyObjects[this.Properties[index]], propertyValue, null);
}&lt;/pre&gt;

&lt;p&gt;Note the block that handles generic types. It doesn’t seem that conversion from string can be handles easier.&lt;/p&gt;</description></item><item><title>Workflows, service buses, sagas…</title><link>http://bloggingabout.net/blogs/vagif/archive/2009/07/08/workflows-service-buses-sagas.aspx</link><pubDate>Wed, 08 Jul 2009 18:37:00 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:481914</guid><dc:creator>VagifAbilov</dc:creator><description>&lt;p&gt;Last few weeks I spent much time playing with Workflow Foundation. The goal was to evaluate WF programming model for the purpose of our projects. We are currently using home grown workflow manager, it helped us quit database deadlocks (yes, we went through sins of long running transactions), but it&amp;rsquo;s implementation is pretty naive and considered by everyone as a milestone on our way to the &lt;em&gt;real thing&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This real thing might be a combination of WF and WCF. This is why I spent some time creating simple WF activities consisting of SendActivity and ReceiveActivity that were introduced in WF with .NET 3.5.&lt;/p&gt;
&lt;p&gt;I have mixed feelings, I must say. Samples look great, as usual, but once you write all code that you have to write in order to make ends meet, the resulting code base does not look very elegant. The question I was trying to answer was if WF/WCF integration can free service component developers from thinking about workflow integration aspects. What I hoped is that developers could focus on exposing WCF contracts to their service components, and the actual orchestration could use those components as building blocks. While this is not very far from truth &amp;ndash; contracts and their implementation don&amp;rsquo;t need to carry workflow-related information (except callback contracts), there is too much to care about integration details to call the integration smooth. One thing that really drives me nuts is configuration. &amp;ldquo;Convention over configuration&amp;rdquo; principle is very hard to implement to make WF and WCF play together. For example, if you want your SendActivity to call a WCF service using programmatically specified address, you have to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In workflow designer define SendActivity&amp;rsquo;s ChannelToken property and assign it a name, let&amp;rsquo;s say sendActivity_ChannelToken &lt;/li&gt;
&lt;li&gt;Expand newly created channel token properties and specify an EndpointName, let&amp;rsquo;s say sendActivity_EndPoint &lt;/li&gt;
&lt;li&gt;In code create an instance of Endpoint with the name &amp;ldquo;sendActivity_EndPoint&amp;rdquo; and assign it the address it needs &lt;/li&gt;
&lt;li&gt;Create an instance of ChannelManagerService and pass custom endpoint (or endpoints) to the constructor &lt;/li&gt;
&lt;li&gt;Obtain a workflow runtime instance and add newly created instance of ChannelManagerService &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make the above process even more challenging, you have to carefully plan last two steps. You can only add ChannelManagerService instance to workflow runtime once, and before the runtime is activated. And you can&amp;rsquo;t later add more endpoints to it. So there&amp;rsquo;s very little you can achive dynamically, all workflows, services and interactions between them are supposed to be configured upfront.&lt;/p&gt;
&lt;p&gt;If this is not enough, WorkflowServiceHost (context-enabled ServiceHost) creates a new workflow runtime for each workflow that is instantiated by its invocation. How expensive is to multiply workflow runtimes is another question (depends on afforded performance cost), but since each extra service (pesistence service, tracking service etc.) follows workflow runtime and must be added to it early enough, doing this runtime preparation each time you want to start a new workflow that contains ReceiveActivity does not look like a good programming model.&lt;/p&gt;
&lt;p&gt;If you want to establish WCF communication between two workflows, you need to save workflow instance Ids and assign them to the channel context in BeforeSend event:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;private void sendActivity_BeforeSend(object sender, SendActivityEventArgs e)
{
    Dictionary context = new Dictionary();
    context.Add(&amp;quot;instanceId&amp;quot;, workflowInstanceId.ToString());
    e.SendActivity.Context = context;
}&lt;/pre&gt;
&lt;p&gt;This is not many lines of extra code, but when you have a powerful workflow designer, you could expect it to take care of such plumbing.&lt;/p&gt;
&lt;p&gt;I look forward to test how WF 4 is going to solve these issues. Apparently smoother integration with WCF was one of the reasons for rewriting it from the ground up. If however I need to choose an enterprise orchestration framework in July 2009, I can as well check out some other options. One interesting alternative is &lt;a target="_blank" href="http://www.nservicebus.com/"&gt;NServiceBus&lt;/a&gt;. It will of course require full review and redesign of communication layer between service components, but we are doing it anyway, so it won&amp;rsquo;t necessarily cost more than adopt the system to use Workflow Foundation. Udi Dahan (a man behind NServiceBus) refers in &lt;a target="_blank" href="http://www.udidahan.com/"&gt;his blog&lt;/a&gt; to &lt;a target="_blank" href="http://www.udidahan.com/2007/12/17/no-more-workflow-for-nservicebus-please-welcome-the-saga/"&gt;Saga concept&lt;/a&gt; &amp;ndash; a model to handle long-running transaction that was first described in 1987 in the &lt;a target="_blank" href="http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf"&gt;article by Garcia Molina and Kenneth Salem&lt;/a&gt;. Since workflow with long-running transactions is our speciality, I continued search for information about Saga and found another project called &lt;a target="_blank" href="http://blog.phatboyg.com/2008/08/28/managing-long-lived-transactions-with-masstransitsaga/"&gt;Massive Transit&lt;/a&gt; that does exactly that. I looked at code examples and I think they are charming. Look for example at &lt;a target="_blank" href="http://blog.phatboyg.com/2009/04/07/declarative-workflow-with-masstransit"&gt;this one&lt;/a&gt;. Yes, both NServiceBus and MassTransit are not workflow frameworks, they are service bus implementations. So you can&amp;rsquo;t just prefer NServiceBus to WF or vice versa, you have to decide first what type of enterprise framework you need. But when all you have is a system built on the pillars of RPC-style communication, your hands are free and both directions seem to be open. Perhaps if I was already working with .NET 4, I would find WF model convincing for the features we need. But WF/WCF integration in .NET 3.5 is painful enough to be more open minded.&lt;/p&gt;</description></item><item><title>WYSIWYG rule editor: create and test rules for any .NET type</title><link>http://bloggingabout.net/blogs/vagif/archive/2009/04/13/wysiwyg-rule-editor-create-and-test-rules-for-any-net-type.aspx</link><pubDate>Mon, 13 Apr 2009 10:34:00 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:481503</guid><dc:creator>VagifAbilov</dc:creator><description>&lt;p&gt;In my &lt;a href="http://bloggingabout.net/blogs/vagif/archive/2009/04/05/rule-engine-with-wysiwyg-rule-serialization.aspx"&gt;previous post&lt;/a&gt; I showed a simple WYSIWYG rule editor (that internally uses Windows Workflow Foundation rule engine) that does not serialize rules using CodeDom notation. I wrote this editor simply to demonstrate the concept, and its code combined both rule editing, rule serialization and sample rule classes. Since I expect rule authoring and management to be hot topic in the projects I am involved, I decided to dedicate some time to clean up the rule editor and make it generic rule authoring tool that can be used with almost any class that can be loaded from an arbitrary .NET assembly.&lt;/p&gt;
&lt;p&gt;Let me start presenting the new editor with a few screen shots that give a pretty good picture of how it can be used.&lt;/p&gt;
&lt;h3&gt;Simple rule editor in action&lt;/h3&gt;
&lt;p&gt;When you start the editor, first thing you need to do is load an assembly that contains types used to build rules.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/SimpleRuleEditor1_5F00_60D72A66.jpg"&gt;&lt;img border="0" width="418" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/SimpleRuleEditor1_5F00_thumb_5F00_0426AFBD.jpg" alt="SimpleRuleEditor1" height="450" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="SimpleRuleEditor1" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve chosen here one of Microsoft Enterprise Library assemblies, Microsoft.Practices.EnterpriseLibrary.Logging.dll. Next is to choose one of its type. Let it be LogEntry.&lt;/p&gt;
&lt;p&gt;Now you can start defining and testing rules, but to make a rule definition task easier, the editor has a helper page that can be displayed by clicking an &amp;ldquo;Info&amp;rdquo; button:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/InfoPage_5F00_0A7016FC.jpg"&gt;&lt;img border="0" width="426" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/InfoPage_5F00_thumb_5F00_2E98023C.jpg" alt="InfoPage" height="358" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="InfoPage" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The Rule Information page is displayed side by side with the main editor form, and it even supports drag and drop, so you can simply drag properties into the &amp;ldquo;Condition&amp;rdquo;, &amp;ldquo;Then&amp;rdquo; or &amp;ldquo;Else&amp;rdquo; text boxes. It can save you from typos, and I was able to quickly define a LogEntry rule: &amp;ldquo;If Severity == TraceEventType.Error and Message.Contains(&amp;ldquo;Space mission&amp;rdquo;) Then Priority = 5&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/LogEntryRule_5F00_6BBBBDC1.jpg"&gt;&lt;img border="0" width="432" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/LogEntryRule_5F00_thumb_5F00_666F67C1.jpg" alt="LogEntryRule" height="464" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="LogEntryRule" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Every rule should be tested, and our editor has an &amp;ldquo;Apply&amp;rdquo; button that displays a rule object data input page. The &amp;ldquo;Value&amp;rdquo; column is editable, so to test the rules we can enter some data there. Of course, the most interesting input is the one that should trigger the rule:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/LogEntryObject1_5F00_17FD6608.jpg"&gt;&lt;img border="0" width="503" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/LogEntryObject1_5F00_thumb_5F00_652FF044.jpg" alt="LogEntryObject1" height="306" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="LogEntryObject1" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;And the rules are invoked by clicking the &amp;ldquo;Execute&amp;rdquo; button.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/LogEntryObject2_5F00_54B77F49.jpg"&gt;&lt;img border="0" width="504" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/LogEntryObject2_5F00_thumb_5F00_51A52154.jpg" alt="LogEntryObject2" height="306" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="LogEntryObject2" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;As you can see, defining and testing a rule on an arbitraty .NET class is a matter of seconds, and the rules can be saved for later use. Now let&amp;rsquo;s inspect how this was done.&lt;/p&gt;
&lt;h3&gt;Loading assembly for type instantiation&lt;/h3&gt;
&lt;p&gt;While the task of assembly selection and loading is trivial, certain extra steps need to be performed to prevent subsequent call to Activator.CreateInstance to fail with FileNotFoundException. And this exception will be thrown if the instantiated types depend on types from other assemblies referenced by the assembly loaded with Assembly.LoadFile. Successful instantiation of types from this assembly requires two steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loading referenced assemblies &lt;/li&gt;
&lt;li&gt;Handling AssemblyResolve event that is fired by the current domain. &lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="brush: csharp;"&gt;private Assembly LoadAssembly(string assemblyPath)
{
    Assembly assembly = Assembly.LoadFile(assemblyPath);
    foreach (AssemblyName assemblyRef in assembly.GetReferencedAssemblies())
    {
        Evidence evidence = new Evidence(
            new object[] { new Zone(SecurityZone.MyComputer) },
            new object[] { });

        string path = Path.Combine(Path.GetDirectoryName(assemblyPath), assemblyRef.Name) + &amp;quot;.dll&amp;quot;;
        if (File.Exists(path))
        {
            AssemblyName asmName = new AssemblyName();
            asmName.Name = assemblyRef.Name;
            asmName.CodeBase = Path.GetDirectoryName(assemblyPath);
            Assembly asm = Assembly.LoadFrom(path, evidence);
        }
    }
    return assembly;
}&lt;/pre&gt;
&lt;p&gt;Code to handle domain-specific events can be added to the application Program class, and the event handlers can be registered right on program startup.&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;[STAThread]
static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (Program.Assemblies.Keys.Contains(args.Name))
    {
        return Program.Assemblies[args.Name];
    }
    return null;
}

static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
    if (!Program.Assemblies.Keys.Contains(args.LoadedAssembly.FullName))
    {
        Program.Assemblies.Add(args.LoadedAssembly.FullName, args.LoadedAssembly);
    }
}&lt;/pre&gt;
&lt;h3&gt;Rule serialization&lt;/h3&gt;
&lt;p&gt;Comparing to my previous post, I moved rule serialization code to a dedicated RuleSetSerializer class but kept it minimalistic. It stores rules in a plain tab-separated text file, and I did this on purpose. As I wrote earlier, I see a great value in keeping serialized rules in a human readable format. Would you have to spend more time on management of SQL queries if they all were converted into CodeDom trees? Would configuration files become more complex to work with if they were stored in binary form? Definitely. This is why I mean it is worth storing a rule &amp;ldquo;if a == 1 then b = 2&amp;rdquo; exactly as it looks. A simple serializer streaming the rules as tab-separated lines is just an example for this rule editor. When storing rules in a database conditions and action lists will most likely be written in different table columns but I would still keep their representation compact in case of non-complicated rule sets.&lt;/p&gt;
&lt;h3&gt;Populating property and method lists&lt;/h3&gt;
&lt;p&gt;There the fun began. I had to flatten property trees and build a list of all properties and methods for the top class and all nested classes. Imagine we create rules on a class called FirstLevelClass that include properties pointing to instances of SecondLevelClass that in turn has a property pointing to an instance of ThirdLevelClass:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public class FirstLevelClass
{
    public string Name { get; set; }
    public string Description { get; set; }
    public SecondLevelClass SecondLevel { get; set; }

    public bool FirstMethod() { return true; }
}

public class SecondLevelClass
{
    public string Name { get; set; }
    public string Description { get; set; }
    public ThirdLevelClass ThirdLevel { get; set; }

    public bool SecondMethod() { return true; }
}

public class ThirdLevelClass
{
    public string Name { get; set; }
    public string Description { get; set; }

    public bool ThirdMethod() { return true; }
}&lt;/pre&gt;
&lt;p&gt;For such class topology the following set of properties and methods should be available for rule assignment:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/FirstLevelClass_5F00_5CD13C4F.jpg"&gt;&lt;img border="0" width="427" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/FirstLevelClass_5F00_thumb_5F00_5BFB6716.jpg" alt="FirstLevelClass" height="359" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="FirstLevelClass" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;To support recursive property resolution, I defined an auxilliary class RuleProperty:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public class RuleProperty
{
    public RuleProperty OwnerProperty { get; set; }
    public Type DeclaringType { get; set; }
    public Type Type { get { return this.PropertyInfo.PropertyType; } }
    public string Name { get { return this.PropertyInfo.Name; } }
    public PropertyInfo PropertyInfo { get; set; }

    public string FullName
    {
        get
        {
            string fullName = this.Name;
            var ownerProperty = this.OwnerProperty;
            while (ownerProperty != null)
            {
                fullName = ownerProperty.Name + &amp;quot;.&amp;quot; + fullName;
                ownerProperty = ownerProperty.OwnerProperty;
            }
            return fullName;
        }
    }
}&lt;/pre&gt;
&lt;p&gt;Then populating property list can be implemented using recursive algorithm:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;private List GetProperties(Type type, RuleProperty ownerProperty)
{
    var properties = new List();

    foreach (var property in from item in type.GetProperties() orderby item.Name select item)
    {
        var ruleProperty = new RuleProperty
        {
            DeclaringType = type,
            OwnerProperty = ownerProperty,
            PropertyInfo = property
        };
        if (property.PropertyType.GetProperties().Count() == 0 ||
            property.PropertyType.FullName.StartsWith(&amp;quot;System.&amp;quot;))
        {
            properties.Add(ruleProperty);
        }
        else if (!property.PropertyType.FullName.StartsWith(&amp;quot;System.&amp;quot;))
        {
            properties.AddRange(GetProperties(property.PropertyType, ruleProperty));
        }
    }

    return properties;
}&lt;/pre&gt;
&lt;p&gt;As you can see, I filtered properties based on system classes to avoid expansion of string properties that otherwise would have been treated as compound properties.&lt;/p&gt;
&lt;h3&gt;Instantiating rule object classes&lt;/h3&gt;
&lt;p&gt;This is something that is only needed to test rules in the editor &amp;ndash; when working with rules using domain specific code you will typically just make a call to an object constructor: &amp;ldquo;myObject = new MyObject()&amp;rdquo;. But the rule editor does not have a convenience of knowledge of what objects it should create. It can only call Activator.CreateInstance, and in case of nested objects it will not be enough &amp;ndash; it will need to traverse the whole object hierarchy, identify properties that requires instantiation of nested objects and call Activator.CreateInstance on them. I placed the code that does it in a method CreateObjectInstance:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public RuleObject CreateObjectInstance()
{
    RuleObject ruleObject = new RuleObject(this.Type);
    Dictionary ownerObjects = new Dictionary();

    for (int index = 0; index &amp;lt; this.Properties.Count; index++)
    {
        object propertyObject;
        if (this.Properties[index].OwnerProperty == null)
        {
            propertyObject = ruleObject.Instance;
        }
        else
        {
            if (!ownerObjects.ContainsKey(this.Properties[index].OwnerProperty))
            {
                object baseObject;
                if (this.Properties[index].OwnerProperty.OwnerProperty == null)
                {
                    baseObject = ruleObject.Instance;
                }
                else
                {
                    baseObject = ownerObjects[this.Properties[index].OwnerProperty.OwnerProperty];
                }
                propertyObject = this.Properties[index].OwnerProperty.PropertyInfo.GetValue(baseObject, null);
                if (propertyObject == null)
                {
                    propertyObject = Activator.CreateInstance(this.Properties[index].DeclaringType);
                }
                ownerObjects.Add(this.Properties[index].OwnerProperty, propertyObject);
                this.Properties[index].OwnerProperty.PropertyInfo.SetValue(baseObject, propertyObject, null);
            }
            else
            {
                propertyObject = ownerObjects[this.Properties[index].OwnerProperty];
            }
        }
        ruleObject.PropertyObjects.Add(this.Properties[index], propertyObject);
    }

    return ruleObject;
}&lt;/pre&gt;
&lt;h3&gt;Assigning and retrieving property values&lt;/h3&gt;
&lt;p&gt;After all these preparations there is only one step left: manage property values. When testing rules, a user of the rule editor should be able assign values to a rule object, execute rules and display property values after rule execution. Code to get and set property values is quite simple:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public void SetPropertyValue(RuleObject ruleObject, int index, object value)
{
    object propertyValue;
    if (this.Properties[index].Type.IsEnum)
    {
        propertyValue = Enum.Parse(this.Properties[index].Type, value.ToString());
    }
    else
    {
        propertyValue = Convert.ChangeType(value, this.Properties[index].Type);
    }
    this.Properties[index].PropertyInfo.SetValue(ruleObject.PropertyObjects[this.Properties[index]], propertyValue, null);
}

public object GetPropertyValue(RuleObject ruleObject, int index)
{
    return this.Properties[index].PropertyInfo.GetValue(ruleObject.PropertyObjects[this.Properties[index]], null);
}&lt;/pre&gt;
&lt;p&gt;The rule editor is now completed and can be used to define and test rules on types from any .NET assembly. You can download the rule editor source code together with a few sample test classes (placed in a different assembly) and a few rules for them stored in text files.&lt;/p&gt;</description></item><item><title>Rule engine with WYSIWYG rule serialization</title><link>http://bloggingabout.net/blogs/vagif/archive/2009/04/05/rule-engine-with-wysiwyg-rule-serialization.aspx</link><pubDate>Sun, 05 Apr 2009 17:30:00 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:481482</guid><dc:creator>VagifAbilov</dc:creator><description>&lt;p&gt;I&amp;rsquo;ve been searching for a rule engine for our projects, and the one that suits our needs is a rule engine that comes with Windows Workflow Foundation. Although Microsoft does not advertise WF rule engine as an independent component that can be used in workflow-less applications, nothing prevents developers from grabbing System.Workflow.Activities.dll and start creating and executing RuleSet instances. The example (with sample project) of how to build and execute stand-alone rule sets can be found in &lt;a href="http://blogs.microsoft.co.il/blogs/bursteg/archive/2006/10/11/RuleExecutionWithoutWorkflow.aspx"&gt;Guy Burstein&amp;rsquo;s blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In principle this should be sufficient to start using WF rule engine in any project that will benefit from rules described in an external storage rather than written directly in application source code. However, something stopped me from replacing my rule-alike patterns with rules that can be executed by WF rule engine. And it was not engine functionality &amp;ndash; the engine is both very powerful and simple to use &amp;ndash; it was such insignificant detail as rule serialization style.&lt;/p&gt;
&lt;p&gt;WF rule engine uses XML serialization with CodeDom expressions. To give you an idea of how a serialized rule might look, I wrote a simple rule that assigned value &amp;ldquo;10&amp;rdquo; to a &amp;ldquo;ServiceFee&amp;rdquo; property and pasted here not the whole rule but only its assignment part. So the meaning of the next 18 lines is just &amp;ldquo;ServiceFee = 10&amp;rdquo;, not more.&lt;/p&gt;
&lt;div style="font-size:10pt;background:white;color:black;font-family:courier new;"&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;RuleStatementAction.CodeDomStatement&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeAssignStatement&lt;/span&gt;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;LinePragma&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;{p1:Null}&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;xmlns:ns0&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeAssignStatement.Left&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePropertyReferenceExpression&lt;/span&gt;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;PropertyName&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;ServiceFee&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePropertyReferenceExpression.TargetObject&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeThisReferenceExpression&lt;/span&gt;&lt;span style="color:blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePropertyReferenceExpression.TargetObject&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePropertyReferenceExpression&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 9&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeAssignStatement.Left&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 10&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeAssignStatement.Right&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 11&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePrimitiveExpression&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 12&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePrimitiveExpression.Value&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 13&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns1:Int32&lt;/span&gt;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;xmlns:ns1&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;10&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns1:Int32&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 14&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePrimitiveExpression.Value&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 15&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodePrimitiveExpression&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 16&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeAssignStatement.Right&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 17&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ns0:CodeAssignStatement&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0px;"&gt;&lt;span style="color:#2b91af;"&gt;&amp;nbsp;&amp;nbsp; 18&lt;/span&gt;&amp;nbsp;&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;RuleStatementAction.CodeDomStatement&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;A simple (and respectful) response to my observation is &amp;ldquo;who cares?&amp;rdquo; Really, why should anyone even check what format is used by an external component to serialize its data? And has it been a case of a graphical editor, I would probably fully share this opinion. Wait, not fully. If you use a component that stores graphics not in JPEG or GIF, but in its own proprietary format, you would probably care. Or at least you would make sure that materials prepared by your graphic designers can be converted into that proprietary format without much hassle.&lt;/p&gt;
&lt;p&gt;The same argument is valid here. And the argument is even stronger, because unlike graphical image that you won&amp;rsquo;t likely be adjusting using a hex editor, it is very tempting to be able to change the statement &amp;ldquo;ServiceFee = 10&amp;rdquo; to &amp;ldquo;ServiceFee = 15&amp;rdquo; by hand. No matter how the rule is physically stored (a database, an XML or a plain text file), there is an advantage that it is both human readable and human writable. Especially during development phase when various rules are created and modified all the times for unit tests and QA, but also in a production phase when a customer can read the content of the rule file over the phone.&lt;/p&gt;
&lt;p&gt;Another aspect is rule authoring. Guy Burstein&amp;rsquo;s sample uses RuleSetDialog class to manage rules. I assume you would like to have a control over rule management (even though RuleSetDialog supports Intellisense) and if your application is configured over the Web then using Windows forms is not even an option. If your configurable rules are based on simple conditions and actions (and I believe this is the common case), ability to represent these rules in a simple form will save you some development efforts.&lt;/p&gt;
&lt;p&gt;The task of making rule serialization format human-friendly is not really difficult, because built-in Workflow Foundation rule engine has an internal parser that has no problem of understanding what &amp;ldquo;ServiceFee = 10&amp;rdquo; means without requiring this sentence to be converted first to CodeDom statement. Unfortunately, System.Workflow.Activities.Rules.Parser is not a public class, so it is not possible to instantiate it without using reflection. But with a little help of Type.GetType and a &lt;a href="http://beaucrawford.net/post/Hacking-into-the-Windows-Workflow-Rules-Engine.aspx"&gt;recent blog post&lt;/a&gt; that focuses exactly on this topic, invoking the internal WF rule parser does not become complicated. In my examples below I will be using with slight modifications the implementation suggested by &lt;a href="http://beaucrawford.net/"&gt;beaucrawford.net&lt;/a&gt;&amp;rsquo;s blog owner (he does not expose his name in the blog).&lt;/p&gt;
&lt;p&gt;So let us now build a simple rule editor that can be used to author and execute rules using Windows Workflow Foundation rule engine. The main requirement to the implementation is that rules should be stored and displayed in a WYSIWIG format, in most cases identical to how you would write them in C#.&lt;/p&gt;
&lt;h4&gt;Does this mean we need to support &amp;ldquo;using&amp;rdquo;?&lt;/h4&gt;
&lt;p&gt;WF rule engine resolves names within the scope of the type of an object that was sent to a RuleExecution constructor. RuleExecution constructor has the following signature:&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;RuleExecution(RuleValidation validation, object thisObject);&lt;/pre&gt;
&lt;p&gt;It is type of &amp;ldquo;thisObject&amp;rdquo; that is used as a base for name resolution. So in case of statement &amp;ldquo;ServiceFee = 10&amp;rdquo; it is assumed that there is a type with a property &amp;ldquo;ServiceFee&amp;rdquo; and it is an instance of this type that is sent for rule execution. In fact, RuleExpressionCondition and RuleAction ToString overrides add &amp;ldquo;this&amp;rdquo; qualifier to emphasize that properties belong to a respective object instance: &amp;ldquo;this.ServiceFee = 10&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;So far so good, and we can probably live with &amp;ldquo;this&amp;rdquo; prefix, although it is a beginning of a compromise with WYSIWIG, but the situation gets worse with enums. Rule expressions tend to need enum values unless they are trivial or completely data driven. And since enum definitions obviously don&amp;rsquo;t belong to &amp;ldquo;thisObject&amp;rdquo; type, you will have to provide fully qualified type name for them:&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;PaymentMethod = MyCompany.PaymentServices.CommonDefinitions.PaymentMethod.CreditCard;&lt;/pre&gt;
&lt;p&gt;Well, it is still understandable but after hand-writing a hundred rules you may start to regret that you gave up RuleSetDialog with its Intellisense support. And there is not much you can do here because rule parser is CodeDom-driven, and anything that does not belong to &amp;ldquo;thisObject&amp;rdquo; instance must be fully qualified, there is no magic here. But unlike Workflow Foundation framework that is domain-neutral, your components are domain-specific and can take advantage of knowledge about namespaces and types that are used in rule definition.&lt;/p&gt;
&lt;p&gt;So I modified the code that invokes WF rule parser to preprocess rule condition and action lists and replace values of known enumerators with fully qualified representations. I also modified the code that displays RuleSet items to perform the opposite conversion. When doing this, I also used opportunity to get rid of &amp;ldquo;this&amp;rdquo; prefixes.&lt;/p&gt;
&lt;p&gt;I should make myself clear: my string conversions are straightforward (they all use string.Replace), so they can&amp;rsquo;t be used for rules of an arbitraty complexity (for example, when a rule condition may contain string literals matching not fully qualified enumerator values). I am not saying however that this approach won&amp;rsquo;t fit your needs. Actually I believe it fits majority of rule sets. At least I am not going to spend a few hours on regex matching just to enable a string pattern &amp;ldquo;PaymentMethod.CreditCard&amp;rdquo; to be used in my rules with any other meaning than enum value.&lt;/p&gt;
&lt;p&gt;So we are now ready to proceed with full WYSIWIG support, and by saying this I mean that you can write a statement &amp;ldquo;PaymentMethod = PaymentMethod.CreditCard&amp;rdquo;, and it will be stored and displayed exactly as you wrote it.&lt;/p&gt;
&lt;h4&gt;Time to define some rules&lt;/h4&gt;
&lt;p&gt;For the purpose of proof of concept we don&amp;rsquo;t need to deal with very complex rules. It&amp;rsquo;s worth however to demonstate some of the advantages of using a powerful rule engine, so next time there is a need to handle configurable rules, it will be easy to decide if it is justified to drag a reference to System.Workflow.Activities assembly into your project.&lt;/p&gt;
&lt;p&gt;Here is a list of criteria that our rules should satisfy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rule sets should be based on different types, e.g. when creating instances of RuleValidation and RuleExecution objects, we should experiment with different &amp;ldquo;thisType&amp;rdquo; and &amp;ldquo;thisObject&amp;rdquo; arguments. This does not add complexity to the rules, but it helps building auxilliary classes in a more generalized fashion. &lt;/li&gt;
&lt;li&gt;Individual rule sets should contain multiple rules. This requirement opens for inspection of rules priority and chaining. &lt;/li&gt;
&lt;li&gt;At least one rule should trigger re-execution of previously evaluated rule. This means that a value that is used inside one rule condition sould later be modified in another rule&amp;rsquo;s action. &lt;/li&gt;
&lt;li&gt;At least one rule should contain a call to a method that invokes a delegate. Use of delegates in rule sets increases their extensibility. &lt;/li&gt;
&lt;li&gt;Executing rules on different data should demonstrate optimized rule evaluation, so expressions that require expensive method calls can be built in such a way that skips their evaluation in case other conditions fails. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will use a traditional domain of Web shops and define two rule sets: one with rules for payments and the second one with rules for shipment. The rule sets will be extremely minimalistic, but they should satisfy the requirements above.&lt;/p&gt;
&lt;h4&gt;Payment rules&lt;/h4&gt;
&lt;p&gt;The base class for payment rules is PaymentDetails which is defined here:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;[Flags]
public enum PaymentMethod
{
    None,
    PayPal = 1,
    CreditCard = 2,
    Any = PayPal | CreditCard
}

public class PaymentDetails
{
    public int Weight { get; set; }
    public decimal OrderAmount { get; set; }
    public decimal ShipmentCost { get; set; }
    public decimal TotalAmount { get; set; }
    public PaymentMethod AvailablePaymentMethods { get; set; }
}&lt;/pre&gt;
&lt;p&gt;There are two rules that are defined for these payment details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If Weight is less than 10, then ShipmentCost is 5, otherwise shipment cost is 10. &lt;/li&gt;
&lt;li&gt;If TotalAmount is less than 20, then AvailablePaymentMethods contain only PayPal, otherwise any payment method is allowed. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rules are very simple, however notice that the second rule is affected by the first rule: available payment methods depend on total amount that in turn depends on shipment cost that depends on weight.&lt;/p&gt;
&lt;h4&gt;Shipment rules&lt;/h4&gt;
&lt;p&gt;Shipment rules are defined based on class ShipmentDetails:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;[Flags]
public enum ShipmentMethod
{
    None,
    FedEx = 1,
    UPS = 2,
    DHL = 4,
    International = UPS | DHL,
    Any = FedEx | UPS | DHL
}

public enum ShipmentPreference
{
    None,
    CostOptimization,
    SpeedOptimization
}

public class ShipmentDetails
{
    internal Func hasPendingOrders;

    public string Country { get; set; }
    public string Address { get; set; }
    public ShipmentMethod AvailableShipmentMethods { get; set; }
    public ShipmentPreference Preference { get; set; }
    public bool HasPendingOrders() { return hasPendingOrders(); }
    public bool ReadyForShipment { get; set; }
}&lt;/pre&gt;
&lt;p&gt;There are also two rules for shipment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If Country is &amp;ldquo;USA&amp;rdquo;, then any shipment methods are available, otherwise only UPS and DHL. &lt;/li&gt;
&lt;li&gt;If shipment is optimized for speed, then it is ready, otherwise it is ready if there are no other pending orders. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first rule is as simple as it looks, but the second rule lets us experience execution of rules with delegate invocation. Pending orders are checked within HasPendingOrders method that invokes a potentially expensive delegate assigned to &amp;ldquo;hasPendingOrders&amp;rdquo; and should only be called when such check is necessary.&lt;/p&gt;
&lt;h4&gt;Simple Rule Editor&lt;/h4&gt;
&lt;p&gt;I usually explorer components by writing unit tests, but in this case it is worth building a simple UI to manage and execute rules. Rules will be administered by people from different departments, some people will write them, other people will test them. So I wanted to get a visual impression of rule management process. What fields should rule editor contain? How easy is to understand what rules do by looking at editor&amp;rsquo;s window? How can people test the rules when defining them?&lt;/p&gt;
&lt;p&gt;So I wrote a simple rule editor. Here how it looks (I loaded with payment rules defined earlier and highlighted the rule for available payment methods):&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/SimpleRuleEditor_5F00_5DA0E201.jpg"&gt;&lt;img border="0" width="440" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/SimpleRuleEditor_5F00_thumb_5F00_780365C9.jpg" alt="SimpleRuleEditor" height="473" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="SimpleRuleEditor" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Using this editor we can quickly define payment and shipment rules. You can download the editor with its source code and rule definition files, and the following table contains all conditions and actions exactly as their are specified in these files:&lt;/p&gt;
&lt;table border="1" width="788" cellpadding="2" cellspacing="0"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td width="71" valign="top"&gt;
&lt;p align="center"&gt;&lt;strong&gt;Rule type&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="79" valign="top"&gt;
&lt;p align="center"&gt;&lt;strong&gt;Rule name&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="47" valign="top"&gt;
&lt;p align="center"&gt;&lt;strong&gt;Priority&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="159" valign="top"&gt;
&lt;p align="center"&gt;&lt;strong&gt;Condition&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="199" valign="top"&gt;
&lt;p align="center"&gt;&lt;strong&gt;Then Action&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="231" valign="top"&gt;
&lt;p align="center"&gt;&lt;strong&gt;Else Action&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="71" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Payment&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="79" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Shipment cost&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="47" valign="top"&gt;
&lt;p align="center"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="159" valign="top"&gt;
&lt;p align="left"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Weight &amp;lt; 10&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="199" valign="top"&gt;
&lt;p align="left"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;ShipmentCost = 5; &lt;br /&gt;TotalAmount = OrderAmount + ShipmentCost&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="231" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;ShipmentCost = 10; &lt;br /&gt;TotalAmount = OrderAmount + ShipmentCost&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="71" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Payment&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="79" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Payment method&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="47" valign="top"&gt;
&lt;p align="center"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="159" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;TotalAmount &amp;lt; 20&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="199" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;AvailablePaymentMethods = PaymentMethod.PayPal&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="231" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;AvailablePaymentMethods = PaymentMethod.Any&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="71" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Shipment&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="79" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Shipment method&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="47" valign="top"&gt;
&lt;p align="center"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="159" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Country == &amp;quot;USA&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="199" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;AvailableShipmentMethods = ShipmentMethod.Any&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="231" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;AvailableShipmentMethods = ShipmentMethod.International&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td width="71" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Shipment&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="79" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Readiness&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="47" valign="top"&gt;
&lt;p align="center"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td width="159" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;Preference == ShipmentPreference. CostOptimization &amp;amp;&amp;amp; HasPendingOrders()&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="199" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;ReadyForShipment = False&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td width="231" valign="top"&gt;&lt;span style="font-size:xx-small;font-family:courier;"&gt;&lt;span style="font-size:x-small;"&gt;ReadyForShipment = True&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The editor&amp;rsquo;s main form has &amp;ldquo;Apply&amp;rdquo; button that can be used to execute the currently loaded rule set on a sample data. The data fill-in form is tailored to match respective rule category.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/PaymentRules_5F00_0A4EBD3D.jpg"&gt;&lt;img border="0" width="190" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/PaymentRules_5F00_thumb_5F00_49AC70CD.jpg" alt="PaymentRules" height="274" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="PaymentRules" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The result of this sample data execution exposes one important WF rule engine feature: re-evaluation of affected rules. As you can see, the total amount is 23, but this value was set only after execution of the &amp;ldquo;Shipment cost&amp;rdquo; rule. If you swap &amp;ldquo;Shipment cost&amp;rdquo; and &amp;ldquo;Payment method&amp;rdquo; rules priorities, so &amp;ldquo;Payment method&amp;rdquo; will be executed first (greater priority value means earlier execution), befor the total order amount is calcuated, the rule set execution result will still be correct. This is because the editor assigns rules chaining behavior to RuleChainingBehavior.Full. If you change chaining behavior to None, then you will have to ensure the rules are executed in correct order, otherwise affected rules will not be re-evaluated.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s load shipment rules and apply them to sample data.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/ShipmentRules1_5F00_4BE8F989.jpg"&gt;&lt;img border="0" width="182" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/ShipmentRules1_5F00_thumb_5F00_150EA543.jpg" alt="ShipmentRules1" height="327" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="ShipmentRules1" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;If we press now &amp;ldquo;Execute&amp;rdquo; button, the rule engine should invoke a method HasPendingOrders that in turn calls a delegate with the following definition:&lt;/p&gt;
&lt;pre name="code" class="c#"&gt;hasPendingOrders = () =&amp;gt; { MessageBox.Show(&amp;quot;Checking pending orders...&amp;quot;);  return this.checkPendingOrders.Checked; }&lt;/pre&gt;
&lt;p&gt;So we should see a message box informing us that the delegate is executed. And here it comes:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/PendingOrders_5F00_7010E4C9.jpg"&gt;&lt;img border="0" width="162" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/PendingOrders_5F00_thumb_5F00_6B9A6402.jpg" alt="PendingOrders" height="111" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="PendingOrders" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s change the sample data, so the shipment is optimized for speed. Since the rule condition says &amp;ldquo;Preference == ShipmentPreference. CostOptimization &amp;amp;&amp;amp; HasPendingOrders()&amp;rdquo; we should expect rule engine to skip a call to HasPendingOrders and proceed straigth to &amp;ldquo;Then&amp;rdquo; action. And it does! No message box is displayed this time, and we can see the rule execution result with status &amp;ldquo;Ready&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/ShipmentRules2_5F00_523260C8.jpg"&gt;&lt;img border="0" width="186" src="http://bloggingabout.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vagif/ShipmentRules2_5F00_thumb_5F00_5739BFD9.jpg" alt="ShipmentRules2" height="334" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" title="ShipmentRules2" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;After playing a few hours with Windows Workflow Foundation rule engine and customizing presentation of rule sets, so they can be stored and displayed in a very compact form that is easy to understand to even non-technical people, I am very positive about using this rule engine in projects that include configurable business rules. I predict reduction in code change requests caused by business rules modifications. With proper definition of rule base classes in many cases it will be sufficient just to redeploy new rules.&lt;/p&gt;</description></item><item><title>SOA &amp;amp; BPM Conference Material</title><link>http://bloggingabout.net/blogs/markwillems/archive/2009/03/06/soa-amp-bpm-conference-material.aspx</link><pubDate>Fri, 06 Mar 2009 12:10:00 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:481276</guid><dc:creator>Mark Willems</dc:creator><description>&lt;p style="margin:0in 0in 0pt;" class="MsoNormal"&gt;&lt;span style="font-size:small;font-family:Calibri;"&gt;At the end of January the SOA &amp;amp; BPM conference&amp;nbsp;was in held in Seattle . I intended to go there but I didn&amp;#39;t get authorisation to go there from my boss unfortunately. There was a lot of information on BizTalk 2009, Dublin, WCF &amp;amp; WF.&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0in 0in 0pt;" class="MsoNormal"&gt;&lt;span style="font-size:small;font-family:Calibri;"&gt;Lucky for me and I guess for a lot of other people that couldn&amp;#39;t attend the conference all content was recorded. So now&amp;nbsp;you can grab some chips and start viewing the sessions that you believe are interesting.&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0in 0in 0pt;" class="MsoNormal"&gt;&lt;span style="font-size:small;font-family:Calibri;"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0in 0in 0pt;" class="MsoNormal"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;span style="font-size:small;"&gt;Here is the link: &lt;/span&gt;&lt;a target="_blank" href="http://soaconference2009.spaces.live.com/default.aspx?wa=wsignin1.0&amp;amp;sa=828988900"&gt;&lt;span style="font-size:small;color:#0000ff;"&gt;http://soaconference2009.spaces.live.com/default.aspx?wa=wsignin1.0&amp;amp;sa=828988900&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0in 0in 0pt;" class="MsoNormal"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;span style="font-size:small;"&gt;And the link to the powerpoint slides:&amp;nbsp;&lt;span style="font-size:11pt;color:#1f497d;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;mso-ansi-language:NL;mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-fareast-language:EN-US;mso-bidi-language:AR-SA;" lang="NL"&gt;&lt;a href="http://cid-00fa6fc7f5db1c07.skydrive.live.com/browse.aspx/.Public"&gt;&lt;span style="color:#0000ff;"&gt;http://cid-00fa6fc7f5db1c07.skydrive.live.com/browse.aspx/.Public&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description></item><item><title>Windows Workflow, Windows Communication Foundation, and BizTalk Server 2006</title><link>http://bloggingabout.net/blogs/mglaser/archive/2006/12/01/Windows-Workflow_2C00_-Windows-Communication-Foundation_2C00_-and-BizTalk-Server-2006.aspx</link><pubDate>Fri, 01 Dec 2006 10:29:46 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:62776</guid><dc:creator>Mike Glaser</dc:creator><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/23806_565x160_Biztalk_M4.jpg" target="_new"&gt;&lt;img height="181" src="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/23806_565x160_Biztalk_M_thumb4.jpg" width="640" align="middle" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/biztalk" target="_blank"&gt;BizTalk Server Developer Center&lt;/a&gt; has been updated to highlight integration with WF and WCF. Finally Microsoft has written a view articles on how they will include and use WF an WCF in BizTalk. Some things of BizTalk will cover the same features (e.g. BRE is very close related to WF).&lt;/p&gt; &lt;p&gt;&lt;a href="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/architecture14.jpg" target="_new"&gt;&lt;img height="60" alt="Reference Application Pack for Retail" hspace="10" src="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/architecture1_thumb3.jpg" width="80" align="left" border="0"&gt;&lt;/a&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/aa905316.aspx" target="_blank"&gt;Reference Application Pack for Retail&lt;/a&gt;&lt;br&gt;This white paper, along with the sample application, showcases integration using service orientation with BizTalk Server 2006, Windows Communication Foundation, and Microsoft Business Scorecard Manager.&lt;/p&gt; &lt;p&gt;&amp;nbsp;  &lt;p&gt;&lt;a href="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/Integration15.jpg" target="_new"&gt;&lt;img height="60" alt="Windows Workflow and BizTalk Server 2006 Code Sample" hspace="10" src="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/Integration1_thumb4.jpg" width="80" align="left" border="0"&gt;&lt;/a&gt;&lt;a href="http://download.microsoft.com/download/b/1/d/b1d9ddf9-88c6-4d4e-abea-4787fdc85bec/wfintegration.exe" target="_blank"&gt;Windows Workflow and BizTalk Server 2006 Code Sample&lt;/a&gt;&lt;br&gt;This sample demonstrates how to integrate Microsoft BizTalk Server 2006 and Windows Workflow Foundation through Web services.  &lt;p&gt;&amp;nbsp;  &lt;p&gt;&lt;a href="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/WindowsVista13.jpg" target="_new"&gt;&lt;img height="60" alt="Windows Workflow Foundation Overview" hspace="10" src="http://bloggingabout.net/UserFiles/Mike%20Glaser/WindowsLiveWriter/WindowsWorkflowWindowsCommunicationFound_1204F/WindowsVista1_thumb2.jpg" width="80" align="left" border="0"&gt;&lt;/a&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms734631.aspx" target="_blank"&gt;Windows Workflow Foundation Overview&lt;/a&gt;&lt;br&gt;Windows Workflow Foundation is the programming model, engine, and tools for quickly building workflow-enabled applications on Windows. It consists of a namespace, an in-process workflow engine, and designers for Visual Studio 2005.  &lt;p&gt;&amp;nbsp;&lt;br&gt;&lt;strong&gt;Summary&lt;br&gt;&lt;/strong&gt;Hopefully MS will give us some more samples on how to use it in a production environment.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="0767317B-992E-4b12-91E0-4F059A8CECA8:6cdaf0d5-63a5-4950-a6bc-e89ae9831318" style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;Technorati tags: &lt;a href="http://technorati.com/tags/WF" rel="tag"&gt;WF&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Workflow" rel="tag"&gt;Workflow&lt;/a&gt;, &lt;a href="http://technorati.com/tags/WCF" rel="tag"&gt;WCF&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Windows%20Communication%20Foundation" rel="tag"&gt;Windows Communication Foundation&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Biztalk" rel="tag"&gt;Biztalk&lt;/a&gt;&lt;/div&gt;</description></item><item><title>Developing Workflows in Visual Studio .NET</title><link>http://bloggingabout.net/blogs/mglaser/archive/2006/12/01/Developing-Workflows-in-Visual-Studio-.NET.aspx</link><pubDate>Fri, 01 Dec 2006 10:06:09 GMT</pubDate><guid isPermaLink="false">813b6dfd-644e-4573-a816-eebab56ba0d0:62772</guid><dc:creator>Mike Glaser</dc:creator><description>&lt;p&gt;Eilene Hao, Program Manager for&amp;nbsp;SharePoint Workflow finished her complete blog series about developing SharePoint workflows in Visual Studio (VS). Lots of people are asking a lot of questions about this issue and a lot of them seem to have common points of confusion.&amp;nbsp;With so much information out there, it’s sometimes hard to see the big picture amidst details and know what’s really important or how to put all the pieces together.&amp;nbsp;&lt;/p&gt; &lt;p&gt;She&amp;nbsp;created&amp;nbsp;a more cohesive guide of key concepts, and converted it to&amp;nbsp;a blog series that she posted&amp;nbsp;&lt;a href="http://blogs.msdn.com/sharepoint/default.aspx" target="_blank"&gt;Microsoft SharePoint Products and Technologies Team Blog&lt;/a&gt;. She started&amp;nbsp;with some&amp;nbsp;fundamental workflow terminology and critical architectural concepts, then go over the steps for developing a workflow, covering the most common questions and points of confusion, and noting pitfalls and tips for success along the way. Understanding the material in this series will hopefully equip you with the right tools and knowledge to solve or work around a lot of problems that you encounter.  &lt;p&gt;Note that this is not a replacement for the SDK, and you should still look there for the finer details.&amp;nbsp;She&amp;nbsp;highlighted the major concepts so that you have a sense of what to look for.  &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/11/18/developing-workflows-in-vs-part-1-workflow-objects-and-a-crash-course-on-mechanics.aspx"&gt;Developing Workflows in VS: Part 1&lt;/a&gt; - Workflow Objects and A Crash Course on Mechanics&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/11/21/developing-workflows-in-vs-part-2-planning-your-workflow-two-things-to-keep-in-mind.aspx"&gt;Developing Workflows in VS: Part 2&lt;/a&gt; - Planning Your Workflow: Two Things to Keep in Mind&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/11/23/developing-workflows-in-vs-part-3-five-steps-for-developing-your-workflow.aspx"&gt;Developing Workflows in VS: Part 3&lt;/a&gt; - Five Steps for Developing Your Workflow&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/11/26/developing-workflows-in-vs-part-4-design-and-bind-your-forms.aspx"&gt;Developing Workflows in VS: Part 4&lt;/a&gt; - Design and Bind Your Forms&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/11/28/developing-workflows-in-vs-part-5-code-your-workflow.aspx"&gt;Developing Workflows in VS: Part 5&lt;/a&gt; - Code Your Workflow&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/11/30/developing-workflows-in-vs-part-6-deploy-and-debug-your-workflow.aspx"&gt;Developing Workflows in VS: Part 6&lt;/a&gt; - Deploy and Debug your workflow&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/sharepoint/archive/2006/12/01/developing-workflows-in-vs-part-7-summary-and-final-thoughts.aspx" target="_blank"&gt;Developing Workflows in VS: Part 7&lt;/a&gt; - Summary and Final Thoughts&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;Perfect set of articles about developing SharePoint workflows in VS. I'll hope the team will give us more blog-series like this.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="0767317B-992E-4b12-91E0-4F059A8CECA8:d4b6e52d-f73d-4f24-a441-f414bb193f26" style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;Technorati tags: &lt;a href="http://technorati.com/tags/WF" rel="tag"&gt;WF&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Workflow" rel="tag"&gt;Workflow&lt;/a&gt;, &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Visual%20Studio%20.NET" rel="tag"&gt;Visual Studio .NET&lt;/a&gt;&lt;/div&gt;</description></item></channel></rss>