I am trying to write a reusable business rule that would take an editable collection property and an int value and add a broken rule to my root if the count of the collection is greater than the value.
So far, I have written the following business rule but I was hoping you can help me optimize it. Somehow it doesn't feel pretty. I would rather specify the type of the collection which is specified when the property is registered than that of the item. All I really need to get out of all this is the count of the collection (regardless of the item type).
I am using CSLA 4.3.12
Thanks
public class CollectionMaxCountRule<C> : PropertyRule
{
private int MaxCount { get; set; }
public CollectionMaxCountRule(IPropertyInfo primaryProperty, int maxCount): base(primaryProperty)
{
MaxCount = maxCount;
PrimaryProperty = primaryProperty;
InputProperties = new List<IPropertyInfo>() { primaryProperty };
AffectedProperties.Add(primaryProperty);
}
protected override void Execute(RuleContext context)
{
ICollection<C> _list = (ICollection<C>)context.InputPropertyValues[PrimaryProperty];
if (_list.Count > MaxCount)
context.AddErrorResult(PrimaryProperty, string.Format("{0} {1}", ResourceFiles.LibraryResources.CollectionMaxCountRule_Error_MaxCount, MaxCount.ToString()));
}
}
It is added using the following:
BusinessRules.AddRule(
new CollectionMaxCountRule<CostEstimate>(CostEstimateCollectionProperty, int.Parse(ConfigurationManager.AppSettings["MaxCostEstimateCount"])));
The rule looks fine to me, although you could just use the non-generic ICollection (or even IList) if all you're after is the count property.
In order for the rule to run though you'll have to put it in the parent and manually run the rule in the OnChildChanged override.
Thank you Andy. You are right the ICollection and IList do work. I was missing the property reference in my class.
Hi,
You could also consider to add generic constraint to the primaryProperty (will give you better typecheck that the property and rule have the same generic constraint) and simplify the rule - just a little bit. And you do NOT have to add PrimaryProperty to AffectedProperties in order to set error result if you use the method that does not take a propertyInfo as parameter (and implicitly defaults to PrimaryProperty)
I try to not use the InputProperties when dealing with list/child lists so my preference would be like this:
public class CollectionMaxCountRule<T> : PropertyRule { private int MaxCount { get; set; } public CollectionMaxCountRule(PropertyInfo<T> primaryProperty, int maxCount) : base(primaryProperty) { MaxCount = maxCount; } protected override void Execute(RuleContext context) { var list = (ICollection<T>)ReadProperty(context.Target, PrimaryProperty); if (list.Count > MaxCount) context.AddErrorResult(string.Format("{0} {1}", "custom error message", MaxCount)); } }
Thanks JonnyBee. I did as you suggested which is very helpful to validate the property type with the rule. However, I wasn't able to use
var list = (ICollection<T>)ReadProperty(context.Target, PrimaryProperty);
because T is the type of the collection and not that of its children.
I simply changed it to:
var list = (ICollection)ReadProperty(context.Target, PrimaryProperty);
Copyright (c) Marimer LLC