Breaking CSLA 4.0 property changes when using private backing fields.

3 min read
Table of Contents

I came across this bug last night, which was occurring right as CSLA 4 was released. It had to deal with the CodeSmith CSLA templates when you set UseMemberVariables to true. The error is quite obscure and not very intuitive as the signs of a bug are only found when you check to see if your business object IsValid. The scenario in this case is when you set a required managed property, the rules never fully evaluate the set value. A bunch of other side effects could occur as well. Here is the error you could receive:

CategoryId required
Expected:True
But was:False

Here is the code that was causing the error:

CSharp

protected override void AddBusinessRules()
{
BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(_categoryIdProperty));
}
private static readonly PropertyInfo<System.String> _categoryIdProperty = RegisterProperty<System.String>(p => p.CategoryId, String.Empty);
private System.String _categoryId = _categoryIdProperty.DefaultValue;
public System.String CategoryId
{
get { return GetProperty(_categoryIdProperty, _categoryId); }
set { SetProperty(_categoryIdProperty, ref _categoryId, value); }
}
[Test]
private void CreateCategory(string categoryID)
{
Category category = Category.NewCategory();
category.CategoryId = categoryID;
Assert.IsTrue(category.IsValid, category.BrokenRulesCollection.ToString());
category = category.Save();
Assert.IsTrue(category.CategoryId == categoryID);
}

Visual Basic

Protected Overrides Sub AddBusinessRules()
BusinessRules.AddRule(New Csla.Rules.CommonRules.Required(_categoryIdProperty))
End Sub
Private Shared ReadOnly _categoryIdProperty As PropertyInfo(Of System.String) = RegisterProperty(Of System.String)(Function(p As Category) p.CategoryId, String.Empty)
Private _categoryId As System.String = _categoryIdProperty.DefaultValue
Public Property CategoryId() As System.String
Get
Return GetProperty(_categoryIdProperty, _categoryId)
End Get
Set (value As System.String)
SetProperty(_categoryIdProperty, _categoryId, value)
End Set
End Property
<test()> _
Private Sub CreateCategory(ByVal categoryID As String)
Dim category As Category = PetShop.Tests.ParameterizedSQL.Category.NewCategory()
category.CategoryId = categoryID
Assert.IsTrue(category.IsValid, category.BrokenRulesCollection.ToString())
category = category.Save()
Assert.IsTrue(category.CategoryId = categoryID)
End Sub

As you can see the code looks and works fine in CSLA 3.8 but it isn’t the case in 4.0. Once I tracked down what was causing the error, I saw that there wasn’t any checks in CSLA4 to see if the property had the RelationshipTypes.PrivateField overload when you are calling the GetProperty or SetProperty methods with a backing field. The long term fix when using private member backing fields is to set the RelationshipTypes to RelationshipTypes.PrivateField.

CSharp

private static readonly PropertyInfo<System.String> _categoryIdProperty = RegisterProperty<System.String>(p => p.CategoryId, String.Empty, RelationshipTypes.PrivateField);
private System.String _categoryId = _categoryIdProperty.DefaultValue;
public System.String CategoryId
{
get { return GetProperty(_categoryIdProperty, _categoryId); }
set { SetProperty(_categoryIdProperty, ref _categoryId, value); }
}

Visual Basic

Private Shared ReadOnly _categoryIdProperty As PropertyInfo(Of System.String) = RegisterProperty(Of System.String)(Function(p As Category) p.CategoryId, String.Empty, RelationshipTypes.PrivateField)
Private _categoryId As System.String = _categoryIdProperty.DefaultValue
Public Property CategoryId() As System.String
Get
Return GetProperty(_categoryIdProperty, _categoryId)
End Get
Set (value As System.String)
SetProperty(_categoryIdProperty, _categoryId, value)
End Set
End Property

This has been fixed in a nightly build of the CodeSmith CSLA Templates and will be in version 3.0.1 of the CodeSmith CSLA Templates. The CSLA team will also be releasing version 4.0.1 of CSLA sometime soon. If you don’t have this overload set in CSLA 4.0.1 then you will receive the following exception:

Properties with private backing fields must be marked as RelationshipTypes.PrivateField

If you are using the CodeSmith CSLA templates, remember to update to the latest templates and regenerate. If you are not, well you should be using the CodeSmith CSLA Templates as it is about to save you a ton of time adding the RelationshipTypes.PrivateField overload to all of your properties!

Blake Niemyjski

Thanks for reading! Feel free to check out more posts or browse by category, and reach out via the social links below.


More Posts

Comments