Vagif Abilov's blog on .NET

April 2009 - Posts

WYSIWYG rule editor: create and test rules for any .NET type

In my previous post 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.

Let me start presenting the new editor with a few screen shots that give a pretty good picture of how it can be used.

Simple rule editor in action

When you start the editor, first thing you need to do is load an assembly that contains types used to build rules.

SimpleRuleEditor1

I’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.

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 “Info” button:

InfoPage

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 “Condition”, “Then” or “Else” text boxes. It can save you from typos, and I was able to quickly define a LogEntry rule: “If Severity == TraceEventType.Error and Message.Contains(“Space mission”) Then Priority = 5”:

LogEntryRule

Every rule should be tested, and our editor has an “Apply” button that displays a rule object data input page. The “Value” 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:

LogEntryObject1

And the rules are invoked by clicking the “Execute” button.

LogEntryObject2

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’s inspect how this was done.

Loading assembly for type instantiation

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:

  • Loading referenced assemblies
  • Handling AssemblyResolve event that is fired by the current domain.
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) + ".dll";
        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;
}

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.

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

Rule serialization

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 “if a == 1 then b = 2” 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.

Populating property and method lists

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:

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

For such class topology the following set of properties and methods should be available for rule assignment:

FirstLevelClass

To support recursive property resolution, I defined an auxilliary class RuleProperty:

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 + "." + fullName;
                ownerProperty = ownerProperty.OwnerProperty;
            }
            return fullName;
        }
    }
}

Then populating property list can be implemented using recursive algorithm:

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("System."))
        {
            properties.Add(ruleProperty);
        }
        else if (!property.PropertyType.FullName.StartsWith("System."))
        {
            properties.AddRange(GetProperties(property.PropertyType, ruleProperty));
        }
    }

    return properties;
}

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.

Instantiating rule object classes

This is something that is only needed to test rules in the editor – when working with rules using domain specific code you will typically just make a call to an object constructor: “myObject = new MyObject()”. 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 – 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:

public RuleObject CreateObjectInstance()
{
    RuleObject ruleObject = new RuleObject(this.Type);
    Dictionary ownerObjects = new Dictionary();

    for (int index = 0; index < 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;
}

Assigning and retrieving property values

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:

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

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.

Rule engine with WYSIWYG rule serialization

I’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 Guy Burstein’s blog.

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 – the engine is both very powerful and simple to use – it was such insignificant detail as rule serialization style.

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 “10” to a “ServiceFee” property and pasted here not the whole rule but only its assignment part. So the meaning of the next 18 lines is just “ServiceFee = 10”, not more.

    1 <RuleStatementAction.CodeDomStatement>

    2     <ns0:CodeAssignStatement LinePragma="{p1:Null}" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

    3         <ns0:CodeAssignStatement.Left>

    4             <ns0:CodePropertyReferenceExpression PropertyName="ServiceFee">

    5                 <ns0:CodePropertyReferenceExpression.TargetObject>

    6                     <ns0:CodeThisReferenceExpression />

    7                 </ns0:CodePropertyReferenceExpression.TargetObject>

    8             </ns0:CodePropertyReferenceExpression>

    9         </ns0:CodeAssignStatement.Left>

   10         <ns0:CodeAssignStatement.Right>

   11             <ns0:CodePrimitiveExpression>

   12                 <ns0:CodePrimitiveExpression.Value>

   13                     <ns1:Int32 xmlns:ns1="clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">10</ns1:Int32>

   14                 </ns0:CodePrimitiveExpression.Value>

   15             </ns0:CodePrimitiveExpression>

   16         </ns0:CodeAssignStatement.Right>

   17     </ns0:CodeAssignStatement>

   18 </RuleStatementAction.CodeDomStatement>

A simple (and respectful) response to my observation is “who cares?” 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.

The same argument is valid here. And the argument is even stronger, because unlike graphical image that you won’t likely be adjusting using a hex editor, it is very tempting to be able to change the statement “ServiceFee = 10” to “ServiceFee = 15” 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.

Another aspect is rule authoring. Guy Burstein’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.

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 “ServiceFee = 10” 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 recent blog post 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 beaucrawford.net’s blog owner (he does not expose his name in the blog).

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

Does this mean we need to support “using”?

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:

RuleExecution(RuleValidation validation, object thisObject);

It is type of “thisObject” that is used as a base for name resolution. So in case of statement “ServiceFee = 10” it is assumed that there is a type with a property “ServiceFee” and it is an instance of this type that is sent for rule execution. In fact, RuleExpressionCondition and RuleAction ToString overrides add “this” qualifier to emphasize that properties belong to a respective object instance: “this.ServiceFee = 10”.

So far so good, and we can probably live with “this” 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’t belong to “thisObject” type, you will have to provide fully qualified type name for them:

PaymentMethod = MyCompany.PaymentServices.CommonDefinitions.PaymentMethod.CreditCard;

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 “thisObject” 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.

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 “this” prefixes.

I should make myself clear: my string conversions are straightforward (they all use string.Replace), so they can’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’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 “PaymentMethod.CreditCard” to be used in my rules with any other meaning than enum value.

So we are now ready to proceed with full WYSIWIG support, and by saying this I mean that you can write a statement “PaymentMethod = PaymentMethod.CreditCard”, and it will be stored and displayed exactly as you wrote it.

Time to define some rules

For the purpose of proof of concept we don’t need to deal with very complex rules. It’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.

Here is a list of criteria that our rules should satisfy:

  • Rule sets should be based on different types, e.g. when creating instances of RuleValidation and RuleExecution objects, we should experiment with different “thisType” and “thisObject” arguments. This does not add complexity to the rules, but it helps building auxilliary classes in a more generalized fashion.
  • Individual rule sets should contain multiple rules. This requirement opens for inspection of rules priority and chaining.
  • 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’s action.
  • At least one rule should contain a call to a method that invokes a delegate. Use of delegates in rule sets increases their extensibility.
  • 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.

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.

Payment rules

The base class for payment rules is PaymentDetails which is defined here:

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

There are two rules that are defined for these payment details:

  • If Weight is less than 10, then ShipmentCost is 5, otherwise shipment cost is 10.
  • If TotalAmount is less than 20, then AvailablePaymentMethods contain only PayPal, otherwise any payment method is allowed.

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.

Shipment rules

Shipment rules are defined based on class ShipmentDetails:

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

There are also two rules for shipment:

  • If Country is “USA”, then any shipment methods are available, otherwise only UPS and DHL.
  • If shipment is optimized for speed, then it is ready, otherwise it is ready if there are no other pending orders.

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 “hasPendingOrders” and should only be called when such check is necessary.

Simple Rule Editor

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’s window? How can people test the rules when defining them?

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

SimpleRuleEditor

 

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:

Rule type

Rule name

Priority

Condition

Then Action

Else Action

Payment Shipment cost

2

Weight < 10

ShipmentCost = 5;
TotalAmount = OrderAmount + ShipmentCost

ShipmentCost = 10;
TotalAmount = OrderAmount + ShipmentCost
Payment Payment method

1

TotalAmount < 20 AvailablePaymentMethods = PaymentMethod.PayPal AvailablePaymentMethods = PaymentMethod.Any
Shipment Shipment method

1

Country == "USA" AvailableShipmentMethods = ShipmentMethod.Any AvailableShipmentMethods = ShipmentMethod.International
Shipment Readiness

2

Preference == ShipmentPreference. CostOptimization && HasPendingOrders() ReadyForShipment = False ReadyForShipment = True

The editor’s main form has “Apply” 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.

PaymentRules

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 “Shipment cost” rule. If you swap “Shipment cost” and “Payment method” rules priorities, so “Payment method” 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.

Now let’s load shipment rules and apply them to sample data.

ShipmentRules1

If we press now “Execute” button, the rule engine should invoke a method HasPendingOrders that in turn calls a delegate with the following definition:

hasPendingOrders = () => { MessageBox.Show("Checking pending orders...");  return this.checkPendingOrders.Checked; }

So we should see a message box informing us that the delegate is executed. And here it comes:

PendingOrders

Now let’s change the sample data, so the shipment is optimized for speed. Since the rule condition says “Preference == ShipmentPreference. CostOptimization && HasPendingOrders()” we should expect rule engine to skip a call to HasPendingOrders and proceed straigth to “Then” action. And it does! No message box is displayed this time, and we can see the rule execution result with status “Ready”:

ShipmentRules2

Conclusion

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.

.NET 3.5 SP1 and WCF coding guidelines

I am curious if POCO support for data contracts in .NET 3.5 SP1 affected coding guidelines. In brief, prior to .NET 3.5 SP1 all data structures that were part of WCF service contracts had to be decorated with DataContract attributes, and in order for their fields to be handled by DataContractSerializer they had to be decorated with DataMember attribute. Latest .NET service pack relaxed this requirement, so now if a class is not marked as DataContract, then all its public properties will be serialized. These two definitions are now equivalent assuming their namespace names match:

[DataContract]
public class Customer : IExtensibleDataObject
{
    [DataMember]
    string FirstName { get; set; }

    [DataMember]
    string LastName { get; set; }

    public ExtensionDataObject ExtensionData { get; set; }
}

public class Customer : IExtensibleDataObject
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public ExtensionDataObject ExtensionData { get; set; }
}

More on WCF serialization programming model.

I checked Juval Lowy’s updated WCF coding standard, and here is quite clear on this subject: “avoid inferred data contracts (POCO). Always be explicit and apply the DataContract attribute.

I can see his point now when .NET classes used in WCF service contracts represent a small fraction of all classes defined in the system. It is similar to early COM years when developers had to place COM interfaces and classes in dedicated IDL files and use MIDL compiler to generate proxy/stub libraries. Now every .NET object is essentially a COM object, and Juval himself predicts that advantages of WCF programming model will eventually make developers write most of their classes as WCF contracts. And the changes in .NET 3.5 SP1 proves that Microsoft wants this transition to be smooth and removes restrictions that prevented standard .NET types to be treated as WCF contracts. So I am not sure which coding standard I would choose today: the one based on a principle “boundaries are explicit” or the one that provides POCO and WCF with unified syntax.