Category Archives: Csla

CSLA-Validation–the new NuGet package in CSLA .NET 4.5.40

Or how to use the Csla 3.6 to 3.8 style rules in Csla 4.5.40

Introduction

Many developers find the move from Csla .NET 3.x to Csla .NET 4.x to be a big hurdle. Especially when it comes to the new rule engine in Csla .NET 4.x. In this article I will take the ProjectTracker.Library project from the Csla .NET 3.6 samples and upgrade to .NET 4.5 with Csla 4.5.40 NuGet packages.

The 3.x rule engine used static methods and the new 4.x rule engine uses classes. The benefit of using classes is inheritance, testability and allow the framework to provide base classes that get to the inner properties and methods of the business objects. The new rule engine also provides the same base classes and signature for both sync and async rules.

Having done several migrations with different approach to how to do the migration (starting with having the “old” Csla in a private renamed assembly and namespace) I finally came up with the idea of how to support most of the older style rules within the new rule engine. As it turns out this was quite simple to do and only required 1 to 3 days of work to get the application up and running on the new version and then the entire team could start to work on migration of the rules.

In order to do a full migration there is several breaking changes that you must handle. These will be covered in a separate blog posts, so for now let us focus on getting the business library with old style rules to work. And keep in mind – your target platform may be . NET 4, .NET 4.5, Silverlight 5, Windows Store or MonoAndroid.

Important breaking changes for rules:

  • There can be only one Authorization rule per AuthorizationAction and IMethodInfo (or property) where the old rule engine allowed multiple rules and both Allow/Deny combinations.
  • AddAuthorizationRules() is now deprecated and these authorization rules should be moved to AddBusinesRules().
  • Rewrite authorization rules to use the new IsInRole() or IsNotInRole() rules.
  • Rewrite asynchronous rules to use the new rule classes.

The changes the we must do is:

  1. Remove references to old Csla assembly and add Csla references from NuGet
  2. Add intermediate base classes if not already present in solution
  3. Add usings to business objects
  4. Change the signature of CanReadProperty, CanWriteProperty and CanExecuteMethod
  5. pdate AuthorizationRules to new IsInRole/IsNotInRole rules
  6. Add usings to business objects
  7. Change the signature of CanReadProperty, CanWriteProperty and CanExecuteMethod pdate AuthorizationRules to new IsInRole/IsNotInRole rules

Step 1: Remove references to old Csla assembly and add Csla references from NuGet

Remove the references to Csla.dll and update target framework for this sample to .NET 4.5.

Then install nuget package csla-updateValitation in ProjectTracker.Library

See: https://www.nuget.org/packages/CSLA-UpdateValidation

For my own preference I changed the solution so that only

  • ProjectTracker.DalEf
  • ProjectTracker.DalLinq
  • ProjectTracker.Library

will be compiled.

Step 2: Add intermediate base classes for BusinessBase and ReadOnlyBase

The first step you must do is to add your own intermediate base classes for Csla business objects, if not already present in you solution. Make sure that these classes inherit from Csla.Validation base classes for BusinessBase and ReadOnlyBase. When your app is fully migrated to Csla 4.x you should change the inheritance to use the standard Csla base classes and remove the reference to Csla.Validation.

[Serializable()]
public class MyBusinessBase<T> : Csla.Validation.BusinessBase<T> where T:MyBusinessBase<T>
  {
    protected override void AddBusinessRules()
    {
      AddAuthorizationRules();
      base.AddBusinessRules();
    }

    [Obsolete("Move code to AddBusinessRules for CSLA 4.x")]
    protected virtual void AddAuthorizationRules()
    {
    }
  }
[Serializable()]
public class MyReadOnlyBase<T> : Csla.Validation.ReadOnlyBase<T> where T:MyReadOnlyBase<T>
  {
    protected override void AddBusinessRules()
    {
      AddAuthorizationRules();
      base.AddBusinessRules();
    }

    [Obsolete("Move code to AddBusinessRules for CSLA 4.x")]
    protected virtual void AddAuthorizationRules()
    {
    }
  }

And make sure that all you business objects and readonly objects inherit from these base classes.

Also take not of how you can add support for AddAuthorizationRules in your own intermediate base class.

Step 3 Add usings to business objects

You should now take the opportunity to add these usings to business objects

using Csla.Validation;
using Csla.Rules;

Step 4: Change the signature of CanReadProperty, CanWriteProperty and CanExecuteMethod

to use the overload that accepts a PropertyInfo or MethodInfo as parameter

Here shown for CanExecuteMethod()

From:

public Resource GetResource()
    {
      CanExecuteMethod("GetResource", true);
      return Resource.GetResource(GetProperty(ResourceIdProperty));
    }

To:

private static MethodInfo GetResourceMethod = RegisterMethod(p => p.GetResource());
    public Resource GetResource()
    {
      CanExecuteMethod(GetResourceMethod, true);
      return Resource.GetResource(GetProperty(ResourceIdProperty));
    }

and take note of how you can get rid of the string constant.

Step 5: Update AuthorizationRules to new IsInRole/IsNotInRole rules

and keep in mind that you can only have one rule per AuthorizationAction and methodinfo.

From:

protected static void AddObjectAuthorizationRules()
    {
      AuthorizationRules.AllowCreate(typeof(Project), "ProjectManager");
      AuthorizationRules.AllowEdit(typeof(Project), "ProjectManager");
      AuthorizationRules.AllowDelete(typeof(Project), "ProjectManager");
      AuthorizationRules.AllowDelete(typeof(Project), "Administrator");
    }

To:

protected static void AddObjectAuthorizationRules()
    {
      BusinessRules.AddRule(typeof(Project), new IsInRole(AuthorizationActions.CreateObject, "ProjectManager"));
      BusinessRules.AddRule(typeof(Project), new IsInRole(AuthorizationActions.EditObject, "ProjectManager"));
      BusinessRules.AddRule(typeof(Project), new IsInRole(AuthorizationActions.CreateObject,"ProjectManager", "Administrator"));
    }

and take note of how we can supply multiple rows on the last rule.

Then do the same updates for Resources.cs

Step 6: Update async rules to use new style classes

See this blog post by Rocky Lhotka on how to write an async business rule

http://www.lhotka.net/weblog/ImplementingAnAsyncRuleInCSLA4Version45.aspx

Step 7: Misc changes for Csla 4.5

Next there is a couple of changes that must be done.

CriteriaBase now has a generic constraint so code must be updated to:

    [Serializable()]
    private class ExistsCommand : CommandBase<ExistsCommand>
And the Windows Forms (BindingList) based classes has been renamed to BusinessBindingListBase and ReadOnlyBindingListBase.
The Csla 4.5 list classes now inherit from ObservableCollection and has slightly different signature on AddNew and events. 
So change from:
BusinssListBase  ==> BusinessBindingListBase

ReadOnlyListBase ==> ReadOnlyBindingListBase

Summary

So this showed how to make the old ProjectTracker.Library compile with Csla .NET 4.5 in .NET 4.5 and use (most) the old style rules. The tecnhique behind this is a set of extension methods that provide the “old” methods and wraps the static methods with a lamda rules. If you want to look at the actual code, the source code can be downloaded from github: https://github.com/MarimerLLC/csla

There is still a number of changes to be done in order to make the entire solution run and this will be a subject for more blog posts.

Hope this encourages you to start migration of your application to Csla .NET 4.5

CSLA 4.5 RuleEngine update

The rule engine for CSLA 4.5.10 has been updated with a new advanced mode.

By default BusinessRules is run as follows when a property is edited by a user:

  1. Call CheckRulesForPropertymethod with parameters Property and Cascade=true
    1. Clear all BrukenRules from the Property
    1. Get list of BusinessRules for Property
    2. Call RunRuleswith parameters RulesForProperty and Cascade=true to run rules for this property.
      1. ForEach rule in RulesForProperty
        1. Call Rule.Execute method
      2. Update property values from context.OuputProperties collection
        1. if value was changed add Property to DirtyProperties
      3. Return RuleResult –  a list of AffectedProperties and lst of DirtyProperties
    3. If  (cascade)
      1. For the aggreate of (context.AffectedProperties from the rules checked) and
        (properties that have BusinessRules with PrimaryProperty as InputProperty)
        take distinct PropertyInfo

        1. call CheckRulesForProperty with parameters Property and Cascade=false.

But then the rule engine stops is rechecking. So the rule engine will only cascade down to the next level and then stop rechecking rules.
The consequence of having properties changed by f.ex. OutputProperties in the second run when Cacade=false is that the Property and RuleResults may get out of sync and a field that has a valid value may be invalid and vice versa.

So this may be a serious problem unless you have taken care of this in designing you business rules. In some financial applications you may also have a lot of calculations that should cascade for all “dirty” properties to rerun rule for as long as properties is changed – much like Excel does in a spreadsheet for calculating formulas  and cascade calculation for as long as cells is updated.

So to provide this level of functionality the RuleEngine for CSLA 4.5.10 has been updated with a new configuration flag:
<bo>.BusinessRules.CascadeOnDirtyProperties.
This is an instance level flag that must be set in the Create/Fetch method of the <bo>.

When CascadeOnDirtyProperties is true the rule engine run rules as follows:

  1. Call CheckRulesForPropertymethod with parameters Property and Cascade=true
    1. Clear all BrukenRules from the Property
    1. Get list of BusinessRules for Property
    2. Call RunRuleswith parameters RulesForProperty and Cascade=true to run rules for this property.
      1. ForEach rule in RulesForProperty
        1. Call Rule.Execute method
      2. Update property values from context.OuputProperties collection
        1. if value was changed add Property to DirtyProperties
      3. Return RuleResult –  a list of AffectedProperties and lst of DirtyProperties
    3. If (cascade)
      1. For the aggreate of (context.AffectedProperties from the rules checked) and
        (properties that have BusinessRules with PrimaryProperty as InputProperty)
        take distinct PropertyInfo

        1. call CheckRulesForProperty with parameters Property and Cascade=true if property is in DirtyProperties list .

Of course – unless your BusinessRules is carefully crafted you may end up with an infinite loop and eventually a StackOverflow exception.
But if you really need to make sure that BusinessRules is actually rerun for as long as property values is updated from context.OutputPropertyValues then this will be a nice extension to the rule engine.

The above sequence diagrams is simplified when it comes to asynchronous rules but the end result is the same behavior for both synchronous and asynchronous rules.

Unit Test CSLA 4 BusinessRules

Unit tests in CSLA 4 is now classes and most developers want to create unit tests to verify the correct behavior and result.
In this article I will show you a suggested way to create these tests.

Basic rule knowledge

Let’s start with how rules is registered in CSLA:

  1. <bo>.AddBusinessRules is only called once and register ALL rules for that object type.
  2. A rule instance should be viewed as a Singelton or Shared object. You cannot store any value elated to the execution (data values) in member variables.

The execution of the rule follow these steps:

  1. The RuleEngine will create an instance of a RuleContext with the actual rule
  2. and if InputProperties have entries copy values from BO to <context>.InputPropertyValues
  3. set <context>.Target property to the <bo> instance (with exception if IsAsync = true and ProvideTargetWhenAsync = false).
  4. call the <rule>.Execute method with <context> as parameter.
  5. When rule has completed call a CompleteHandler for both synchronous and async rules.

The rule engine will call the completed handler automatically for syncronous rules but for async rules your code is responsible for calling <context>.Complete in ALL execution paths.
The <rule>.Execute method is always called inline and when IsAsync = true the assumption is that your code in Execute will do an asyncronous call an in order to notify the rule engine when the rule is completed your code must call <rule>.Complete.

Then take a look at the <rule>.Execute method.

A: Your rule does NOT use <context>.Target and has no relationship to the actual BO.
These rules only interact with the RuleContext and use <context>.InputPropertyValues for input values and may call <context>.AddOutValue or context.AddXYZResult.

The output from these rules is in

  • <context>.Results
  • <context>.OuputPropertyValues

B: Your uses uses <context>.Target and the support methods in BusinessRule base class for ReadProperty or LoadProperty.
These rules interact with the BO and uses methods in BusinessRule base class that expects an actual CSLA BO to be present (implements Csla.Core.IManageProperties).

The output of a rule can be

The output from these rules is in

  • <context>.Results
  • <context>.OuputPropertyValues
  • directly updated properties in the context.Target or child object from calling <rule>.LoadProperty

RuleContext support for result

context.Results is a list of RuleResult that yon can add test for. <context>.AddXYZResult will all add a RuleResult to context.Results.
context.OutputPropertyValues is a dictionary of IPropertyInfo and values to be set in the bo.

So we should be able to create unit tests for both

  • synchreonous rules and async rules
  • rules that only interacts with the rule context.
  • rules that interacts with the context.Target

Support methods in CSLA

RuleContext has a constructor specifically designed for use in unit tests:

public RuleContext(Action<RuleContext> completeHandler, IBusinessRule rule, object target, Dictionary<Csla.Core.IPropertyInfo, object> inputPropertyValues)

that allows the test code to specify the

  • completeHandler for callback when rule has completed.
  • the actual business ruleyou want to test
  • the target object (may be null if your rule does not use the context.Target)
  • a dictionary of input property values

Support class BusinessRuleTest.cs in RuleTutorial samples download

adds more support for tests and will allow you to write the exact same test code whether the rule is syncronous or not.
This is done by adding a CompleteEeventHandler that will wait for up to 3 seconds on an async rule before calling <context>.Complete.

public void InitializeTest(IBusinessRule rule, object target)
public void ExecuteRule()
public void ExecuteRule(Dictionary<IPropertyInfo, object> inputPropertyValues)
public T GetOutputPropertyValue<T>(PropertyInfo<T> propertyInfo)

The ExeuteRule method will copy values from target object to input property values and then call rule.Execute
The ExecuteRule with InputPropertyValues dictionary will just set thes into the context and call rule.Execute.

Then to the unit tests

My proposed solution for creating unit tests uses the constructor in RuleContext, the BusinessRuleTest base class and creating fake business objects for the tests.

I like the testing approach from Phil Haack and Brad Wilson so these sample tests use a separate class for each method.
Read more here: http://haacked.com/archive/2012/01/01/structuring-unit-tests.aspx

Testing a ToUpper transformation rule that makes sure a property is always uppercase.

This rule only interacts with the <context>.InputPropertyValues and <context>.OuputPropertyValues

My fake root object:

  [Serializable]
  public class RootFake : BusinessBase<RootFake>
  {
    public static readonly PropertyInfo<int> CustomerIdProperty = RegisterProperty<int>(c => c.CustomerId);
    public int CustomerId
    {
      get { return GetProperty(CustomerIdProperty); }
      set { SetProperty(CustomerIdProperty, value); }
    }

    public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
    public string Name
    {
      get { return GetProperty(NameProperty); }
      set { SetProperty(NameProperty, value); }
    }
  }

The the test class for constructor:

    [TestClass()]
    public class TheCtor
    {
      private IBusinessRule Rule;
      [TestInitialize]
      public void InitTests()
      {
        Rule = new ToUpper(RootFake.NameProperty);
      }

      [TestMethod]
      public void IsSync()
      {
        Assert.IsFalse(Rule.IsAsync);
      }

      [TestMethod]
      public void HasPrimaryProperty()
      {
        Assert.IsNotNull(Rule.PrimaryProperty);
        Assert.AreEqual(RootFake.NameProperty, Rule.PrimaryProperty);
      }

      [TestMethod]
      public void HasInputProperties()
      {
        Assert.IsTrue(Rule.InputProperties.Contains(RootFake.NameProperty));
      }

      [TestMethod]
      public void HasAffectedProperties()
      {
        Assert.IsTrue(Rule.AffectedProperties.Contains(RootFake.NameProperty));
      }
    }

Then testing the Execute method with supplied InputPropertyValues:

    [TestClass()]
    public class TheExecuteMethod : BusinessRuleTest
    {
      [TestInitialize]
      public void InitTests()
      {
        var rule = new ToUpper(RootFake.NameProperty);
        InitializeTest(rule, null);
      }

      [TestMethod]
      public void MustSetOutputPropertyToUpper()
      {
        var expected = "CSLA ROCKS";
        ExecuteRule(new Dictionary<IPropertyInfo, object>() {{RootFake.NameProperty, "csla rocks"}});
        Assert.IsTrue(GetOutputPropertyValue(RootFake.NameProperty) == expected);
      }
    }

Then testing the Execute method with a fake object to supply the property value:

    [TestClass()]
    public class TheExecuteMethodAlt : BusinessRuleTest
    {
      [TestInitialize]
      public void InitTests()
      {
        var rule = new ToUpper(RootFake.NameProperty);
        var root = new RootFake();
        root.Name = "csla rocks";
        InitializeTest(rule, root);
      }

      [TestMethod]
      public void MustSetOutputPropertyToUpper()
      {
        var expected = "CSLA ROCKS";
        ExecuteRule();
        Assert.IsTrue(GetOutputPropertyValue(RootFake.NameProperty) == expected);
      }
    }

Summary

I hope this gave you a better understanding of how Business Rules work and what to test.

You will find more unit test samples in the Net\cs\RuleTutorial sample available at http://www.lhotka.net/cslanet/download.aspx and if you have questions please post on the CSLA,NET Forum at http://forums.lhotka.net

CSLA 4.2 Rules update

The CSLA rule engine had a major change when moving from 3.8.x to 4.0. The major change being that rules is now classes and inheritable whereas the earlier rules were static methods.

For the upcoming CSLA 4.2 release we have made a number of bug fixes plus added some new features that you should be aware of.

1. InputProperties is now also considered Dependencies just as AffectedProperties.

Take for example the validation of StartDate and EndDate where StartDate must be before EndDate.

In CSLA 4.0/4.1 you would have to add:

 1: BusinessRules.AddRule(new LessThan(StartDateProperty, EndDateProperty));
 2: BusinessRules.AddRule(new Dependency(EndDateProperty, StartDateProperty));
 3:  
 4: BusinessRules.AddRule(new GreaterThan(EndDateProperty, StartDateProperty));
 5: BusinessRules.AddRule(new Dependency(StartDateProperty, EndDateProperty));

In order to make the validation rules execute as expected, ie,  StartDateProperty must be validated when StartDate is changed or EndDate is changed (Dependency) and EndDate vice versa.
It’s very easy to miss the dependencies so in CSLA 4.2 you will only need:

 1:  BusinessRules.AddRule(new LessThan(StartDateProperty, EndDateProperty));
 2:  BusinessRules.AddRule(new GreaterThan(EndDateProperty, StartDateProperty));

And both rules will be executed when either of the property values is changed.

Having Dependency rules will NOT break your code so the code sample with Dependency rules will run exactly the same way as the last sample.

2. Provide overloads to set your own message text

When you register a rule you may now also specify either a constant message string (MessageText) or a lambda expression (MessageDelegate) to fetch a string from a resource file.
Using the lambda version you can support translation/localization of the message.

NOTE: The formatting function is supported in just the same way as the default messages.

Using a constant string:

 1:       BusinessRules.AddRule(new Required(NameProperty){MessageText = "Customer must have name"});
 2:       BusinessRules.AddRule(new MaxLength(NameProperty, 50){Priority = 1, MessageText = "{0} cannot be longer than {1} chars"});
 3:       BusinessRules.AddRule(new MinValue<int>(Num1Property, 5) { MessageText = "Num1 must be larger than or equal to {1}" });

Using a lambda to support localization:

 1:       BusinessRules.AddRule(new Required(NameProperty){MessageDelegate = () => Resources.NameRequired});
 2:       BusinessRules.AddRule(new MaxLength(NameProperty, 50){Priority = 1, MessageDelegate = () => Resources.NameMaxLength});
 3:       BusinessRules.AddRule(new MinValue<int>(Num1Property, 5) { MessageDelegate = () => Resources.Num1MinValue });

This properties/delegate is implemented in the base classes, your own rules must make sure to override the GetMessage method to provide the default (and preferably) localizable message text.

 1:     protected override string GetMessage()
 2:     {
 3:       return HasMessageDelegate ? base.GetMessage() : Resources.AnyRequiredRule;
 4:     }

3. Rules for affected properties on an Async rule is automatically rerun and UI notified when context.Complete is called.

This was missing pre 4.2 so when an async rule would lookup information in a database and set a number of
properties in the <bo> the rules for those properties were not rechecked. This would cause the field content
and error/warn/info messages to get out of sync.

4. Rules can now specify conditions for when the rule is not allowed to run.

Typical usage is for any rule that you will only allow to run when the user edits a value and f.ex do an async lookup to a database.
By default and to not brake any existing code, rules will run without restrictions.

Flag Property rule Object rule
CanRunInCheckRules         Yes           Yes
CanRunAsAffectedProperty         Yes           No
CanRunOnServer         Yes           No

Object level rules is executed when either <bo>.CheckObjectRules() or <bo>.CheckRules() is called.

PropertyRules is executed when either <bo>.PropertyHasChanged(property) or <bo>.CheckRules() is called.
And PropertyHasChanged is implicitly called when SetProperty changes a value so most developers will never call PropertyHasChanged.

CanRunInCheckRules when false means that the rule will not be executed when <bo>.CheckRules() is called.

CanRunAsAffectedProperty when false means that this property rule will not run when this property is an affected property on another property rule.

CanRunOnServer when false means that this property rule will not run on the “logical” server side, by all practical means in Data Access Layer.
So when CheckRules is called from Data Access do not execute this rule when set to false.

5. New rule base classes

Two new base classes is introduced:

Class name Description
ObjectRule For an object level rule. Will always have PrimaryProperty = null.
PropertyRule For a property level rule. Must always have a PrimaryProperty.

 

All Property validation rules shipped in CommonRules have this inheritance hierarchy:

BusinessRule
– PropertyRule
– CommonBusinessRule
– Actual Rule

So if your own rules inherit from CommonBusinessRule then you will automatically inherit from PropertyRule.

To make this easier for your developers consider adding your own base classes like:

 1:   public abstract class SyncLookupRule : CommonBusinessRule
 2:   {
 3:     protected SyncLookupRule(IPropertyInfo primaryProperty) : base(primaryProperty)
 4:     {
 5:       IsAsync = false;
 6:       CanRunAsAffectedProperty = false;
 7:       CanRunInCheckRules = false;
 8:       CanRunOnServer = false;
 9:     }
 10:   }

and/or

 1:   public abstract class AsyncLookupRule : CommonBusinessRule
 2:   {
 3:     protected AsyncLookupRule(IPropertyInfo primaryProperty) : base(primaryProperty)
 4:     {
 5:       IsAsync = true;
 6:       CanRunAsAffectedProperty = false;
 7:       CanRunInCheckRules = false;
 8:       CanRunOnServer = false;
 9:     }
 10: 

for Sync and Async lookup rules that will only run when a property is changed by user or code.

Identify patterns and stereotypes of rules in your app and create more base classes. You can share them with us on the CslaContrib site

6. Both Object and Property rules can set Error/Warning/Info on other properties, and even co-exist.

This feature would seem possible with Csla 4.0/4.1 but never worked properly. These issues are now fixed and will even allow a
property level rule to set error/warning/info message on other properties than the Primary property.

This AnyRequired rule will make sure that at least one of the fields must have a value and if broken sets ErrorMessage on all fields:

 1:   public class AnyRequired : CommonBusinessRule
 2:   {
 3:     public AnyRequired(IPropertyInfo primaryProperty, params IPropertyInfo[] additionalProperties)
 4:       : base(primaryProperty)
 5:     {
 6:       InputProperties = new List<IPropertyInfo>() {primaryProperty};
 7:       InputProperties.AddRange(additionalProperties);
 8:     }
 9:  
 10:     protected override string GetMessage()
 11:     {
 12:       return HasMessageDelegate ? base.GetMessage() : Resources.AnyRequiredRule;
 13:     }
 14: 
 15:     protected override void Execute(RuleContext context)
 16:     {
 17:       // if all values are Null or Empty
 18:       if (context.InputPropertyValues.Select(keyvalue => keyvalue.Value.ToString().Trim()).All(string.IsNullOrEmpty))
 19:       {
 20:         var fieldNames = string.Join(", ", context.InputPropertyValues.Select(p =>p.Key.FriendlyName));
 21:  
 22:         foreach (var field in context.InputPropertyValues)
 23:         {
 24:           context.Results.Add(new RuleResult(this.RuleName, field.Key, string.Format(GetMessage(), fieldNames)) { Severity = this.Severity });
 25:         }
 26:       }
 27:     }
 28:   }

usage:
 1:     BusinessRules.AddRule(new AnyRequired(NameProperty, Name2Property, Name3Property));

Summary

This post gives a brief introduction to the enhancements that is made in the Rule engine for Csla 4.2.

Stay tuned for more updates. My next posts will dive into different types of rules and how to implement these.
All code I use here can be found the RuleTutorial sample that will be in the Samples download.
At time of publishing this sample is not included in the Csla 4.2 Alfa release so you must get latest version from trunk to get the code.

CslaContrib.MEF and Repository pattern with Csla4

Introduction

MEF has become a standard component in .NET4 and so become an easy starting point for developers for IoC and much more.

In this article I will focus how you can easily use MEF to create an injectable Repository data access into  your Csla business objects. This will help you to create more testable code as your unit tests can inject their own implementation of data access or even just fake som data access. The accompanying sample code uses DataPortal_XYZ methods and can be downloaded from http://cslacontrib.codeplex.com

Csla implements several design patterns including Mobile Objects and Factory methods. So your business objects should not know if the data access happens inline (one-tier) or  on a server (two-tier). This is handled by configuration of the DataPortal and the sample code shown here will work in both configurations.

The Repository pattern is widely described in other articles but here is short introduction for typical usage in Csla:

  1. You have a known set of repository data access objects.
  2. You have defined Interfaces for your data access code.
  3. You want to inject the data access code into your BO.

Ioc static class

The Ioc static class holds the MEF container and will initialized when first call is made. This class also provides a method for test code to supply an externally configured container for data access or fake data.

Custom base classes

The first step is to create custom base classes. This will be the base classes that your BOs inherit from and will make sure to provide the Imports in your objects.

These classes must handle the OnDataPortalInvoke, OnDeserialized and Child_OnDataPortalInvoke (when applicable) events to inject dependencies.

The OnDataPortalInvoke is called by the DataPortal before it call the DataPortal_XYZ methods in both one-tier and two-tier configuration.
The Child_OnDataPortalInvoke is called by the ChildDataPortal beore it call the Child_XYZ methods.
the OnDeserialized is called when the object is deserialized on server or client.

Sample code for MefBusinessBase:

  public class MefBusinessBase<T> : BusinessBase<T> where T : BusinessBase<T>  
  {    
    protected override void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)    
    {      
       Inject();       //inject dependencies into instance      
       base.DataPortal_OnDataPortalInvoke(e);    //call base class   
    }     

    protected override void Child_OnDataPortalInvoke(DataPortalEventArgs e)    
    {          
       Inject();      //inject dependencies into instance      

       base.Child_OnDataPortalInvoke(e);   //call base class    
    }   

    protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)    
    {      
       Inject();      
       base.OnDeserialized(context);    
    } 

    private void Inject()    
    {      
       Ioc.Container.ComposeParts(this);    
    }  
  }

The following classes are supplied in CslaContrib.MEF:

MefBusinessBase
MefBusinessBindingListBase
MefBusinessListBase
MefCommandBase
MefDynamicBindingListBase
MefDynamicListBase
MefNameValueList
MefReadOnlyBase
MefReadOnlyBindingList
MefReadOnlyListBase

Define repository object and data access

In order to use IoC you will create interfaces for the data access code and known repository objects. The smallest samples I could think of is shown here:

  public interface IRootDataAccess  
  {    
     RootData Get(int id);  
  }   

  public class RootData  
  {    
    public int Id { get; set; }    
    public string Name { get; set; }  
  } 

Use MEF to satisfy Imports in your data access

Define injectable properties in your business objects like this:

    [NonSerialized, NotUndoable]    
    private IRootDataAccess _myRootDataAccess;

    [Import(typeof(IRootDataAccess))]    
    public IRootDataAccess MyRootDataAccess    
    {
       get { return _myRootDataAccess; }
       set { _myRootDataAccess = value; }
     }
 Note – You must use a private backing field and mark the field as both NonSerialized and NotUndoable as injected properties should NOT be included in a two-tier application nor be part of the N-Level undo. 

So the data access would look like this:

    public static MyRoot GetRoot(int id)
    {
       return DataPortal.Fetch<MyRoot>(id);
    }    

    public void DataPortal_Fetch(int criteria)
    {
      var data = MyRootDataAccess.Get(criteria);
      using (BypassPropertyChecks) 
      { 
        Id = data.Id; 
        Name = data.Name; 
      }    
   }
In the fetch method the BusinessObject has been supplied with a repository object and knows that this object has a Get method that accepts an int parameter. 

DataAccess classes

 

 

Create classes that Export and implement the data access interfaces:

  [Export(typeof(IRootDataAccess))]
  public class MyRootDataAccess : IRootDataAccess
  {
    public RootData Get(int id)
    {
      return new RootData() { Id = id, Name = "Ole Olsen" };
    }
  }


The Ioc static class will load Exports from all assemblies in the current folder and the executing assembly (for a client application). So when your business objects inherits from the MefXYZ base classes  you will automatically get the available Exports which in your production environment should only be the production assemblies (no test assemblies). 

The good thing here is that when you create unit tests – you can supply your own configured container to the IoC class that will typically do fake data access while the production code will do actual data acces to a database or webservice.

  

I hope this will encourage and help you to use MEF if you want to use the repository pattern in a Csla project. All sample code can be found in the Samples folder in CslaContrib and the CslaContrib.MEF project is in the CslaContrib trunk.

 

Forms DataBinding – The magic sequence of BindUI/UnbindUI

If you are developing Windows Forms apps and using Csla you may get errors like “EditLevelMismatch in CopyState” or se that data values are overwritten when the dataobject is connected to the UI, diconnected from the UI or when the Form is disposed. And often/typically this happends when ComboBoxes are used on the form.

The reasion this happends is because you are making logical errors in your code with regards to DataBinding.

Csla 3.6 introduces the CslaActionExtender and additional helper classes to automate BindUI and UnbindUI but there are times when you really need to do this manually and this article will show you how to this in a proper way. The CslaActionExtender is covered in Rockys book “Expert C# 2008 Business Objects” so I will not cover here.

Whenever it is necessary to handle Bund/Unbind manually I always recommend to create the following methods in your form:

private void BindUI()
{
    // Bind ComboBox list datasources first 
    BindingHelper.RebindBindingSource(customerTypeNameValueListBindingSource,
                                        CustomerTypeNameValueList.GetNameValueList());

    // Bind dataobjects - starting with root object, child, grandchild and so on....
    BindingHelper.RebindBindingSource(testRootBindingSource, MyRoot);
}

private void UnbindUI(bool cancel)
{
    // Unbind in the opposite sequence of BindUI
    BindingHelper.UnbindBindingSource(testRootBindingSource, cancel, true);
    BindingHelper.UnbindBindingSource(customerTypeNameValueListBindingSource, false, false);
}

The correct sequence for BindUI is:

  1. First always bind the datasorces for lists used in ComboBoxes
  2. Next bind the root object
  3. If needed bind the child and grand child objects in that order

The correct sequence for Unbind is the reverse sequence of BindUI.

Why is the sequence so important? When databinding is active on one of the properties SelectedValue, SelectedItem or Text on a ComboBox the value vill be written to the underlying boound property when the prtoperty value is changed. This will happen if the list items does not exist or is removed whild databinding is active. So the key is to make sure that list items exists before the dataobject is connected to BindingSource (bound) and list items are removed only after the dataobject has been disconnected (unbound).

The last pitfall is if you (the developer) does not disconnect dataobjects from the UI when the form is closed. The sequence og disposing BindingSource will be undetermined and may or may not cause the same problems. To fix this you should always make sure to call UnbindUI in the FormClosed event.

    private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
    {
      UnbindUI(true);
    }

The sematics for Save operation is as follows:

  private void SaveMyRoot()
  {
    // assumes dataobject is valid for save, should thest for IsSavable

    UnbindUI(false);
    try
    {
      MyRoot = MyRoot.Save();
    }
    catch (DataPortalException ex)
    {
      // Handle exception the way you waant
    }
    finally
    {
      BindUI();
    }

If you download the code from CslaContrib you will find a small helper class in MyCsla.Windows.BindingHelper that helps you to do a correct Bind and Unbind:

public static class BindingHelper
{

	/// 
	/// Unbinds the binding source and the Data object. Use this Method to safely disconnect the data object from a BindingSource before saving data.
	/// 
	/// The source.
	/// if set to true then call CancelEdit else call EndEdit.
	/// if set to true this BindingSource contains the Root object. Set to false for nested BindingSources
	public static void UnbindBindingSource(BindingSource source, bool cancel, bool isRoot)
	{
		IEditableObject current = null;
		// position may be -1 if bindigsource is already unbound which results in Exception when trying to address current
		if ((source.DataSource != null) && (source.Position > -1)) {
			current = source.Current as IEditableObject;
		}

		// set Raise list changed to True
		source.RaiseListChangedEvents = false;
		// tell currency manager to suspend binding
		source.SuspendBinding();

		if (isRoot) source.DataSource = null;
		if (current == null) return;

		if (cancel)
		{
			current.CancelEdit();
		}
		else
		{
			current.EndEdit();
		}
	}

	/// 
	/// Rebinds the binding source.
	/// 
	/// The source.
	/// The data.
	public static void RebindBindingSource(BindingSource source, object data)
	{
		RebindBindingSource(source, data, false);
	}


	/// 
	/// Rebinds the binding source.
	/// 
	/// The source.
	/// The data.
	/// if set to true then metadata (ovject/list type) was changed.
	public static void RebindBindingSource(BindingSource source, object data, bool metadataChanged)
	{
		if (data != null)
		{
			source.DataSource = data;
		}

		// set Raise list changed to True
		source.RaiseListChangedEvents = true;
		// tell currency manager to resume binding 
		source.ResumeBinding();
		// Notify UI controls that the dataobject/list was reset - and if metadata was changed 
		source.ResetBindings(metadataChanged);
	}
}

Using custom FieldData in Csla 3.1.7 for Net 2.0

Jason Bock wrote a great article on his blog about Creating custom Fielddata classes in Csla that requires Csla 3.7.1 of newer for .Net 3.5 Sp1. If you havent already read his article please do to get a better understanding of what custom FieldData can bring to your Csla solution.

However most of my worktime is using the Csla 3.71. for .Net 2.0 so how could I use these custom fielddata in a .Net 2.0 solution and still be able to port/recompile my code with Csla 3.7.1 for .Net 3.5?

Our customers/users have also requested our apps to be more precise in determining if data has been changed or not, ie has the propertyValue actually changed from the originalvalue. The introduction of custom field data would give us this with minimal effort. I can also vision custom FieldData beein used for auditing purposes because they may track both original and new field value.

The business objects in Jasons sample uses RegisterProperty with lambdas that are actually Expressions. So I had to alter my intermediate classes in MyCsla to add new registerProperty overloads that take a string propertyName instead of a lambda expression.  Latest version of MyCsla for Csla 3.7.1 N2 and the entire CunstomFieldData sample project is available for download on the CslaContrib project on CodePlex.

  [Serializable]
  public class BusinessBase<T> : Csla.BusinessBase<T> where T : BusinessBase<T>
  {
    #region RegisterProperty
    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName));
    }

    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName));
    }

    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, RelationshipTypes relationship)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, relationship));
    }

    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue));
    }

    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue, RelationshipTypes relationship)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue, relationship));
    }
    #endregion
  }

Next we need to alter BusinessCore base class in CustomFieldData project to inherit from MyCsla.BusinessBase  to get the new RegisterProperty overloads:

  [Serializable]
  public abstract class BusinessCore : MyCsla.BusinessBase where T: BusinessCore

And finally change the test business object to use the new RegisterProperty.

  [Serializable]
  public sealed class Person : BusinessCore
  {
    private static PropertyInfo ageProperty =
	                    RegisterProperty("Age");
    private static PropertyInfo firstNameProperty =
			    RegisterProperty("FirstName", "Friendly first name");
    private static PropertyInfo lastNameProperty =
			    RegisterProperty("LastName", "Friendly lastname", String.Empty);

And thats just about it. The custom FieldData works great!!

Download the latest version of MyCsla for Csla 3.7.1 for N2 with CustomFieldData project from CslaContrib

[Serializable]
public class BusinessBase<T> : Csla.BusinessBase<T> where T : BusinessBase<T>
{
#region RegisterProperty
protected static PropertyInfo<P> RegisterProperty<P>(string propertyName)
{
return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName));
}protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName)
{
return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName));
}protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, RelationshipTypes relationship)
{
return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, relationship));
}

protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue)
{
return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue));
}

protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue, RelationshipTypes relationship)
{
return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue, relationship));
}
#endregion

protected override void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
{
Debug.Print(“DataPortalInvoke object:{0}, operation:{1}”, e.ObjectType, e.Operation);
base.DataPortal_OnDataPortalInvoke(e);
}

protected override void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
{
Debug.Print(“DataPortalInvokeCompleted object:{0}, operation:{1}”, e.ObjectType, e.Operation);
base.DataPortal_OnDataPortalInvokeComplete(e);
}

protected override void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
{
Debug.Print(“DataPortalExeption object:{0}, operation:{1}, exception:{2}”, e.ObjectType, e.Operation, ex);
base.DataPortal_OnDataPortalException(e, ex);
}

}