Hi
My code below works as expected in a unit test but fails when using the MVC CslaModelBinder. In this case OnChildChanged is not called. I think also it would be better if I could invoke the sibling rules only when the child object's rule gets broken. Can you help?
Thanks
Andrew
[TestClass]
public class EditableRootTest
{
[TestMethod]
public void AddDuplicateEmails_BothShouldBeInvalid()
{
var account = EditableRoot.New();
account.Email1.EmailAddress = "dup@emailagain.com";
account.Email2.EmailAddress = "dup@emailagain.com";
Assert.AreEqual(false, account.Email1.IsValid);
Assert.AreEqual(false, account.Email2.IsValid);
}
}
[Serializable]
public class EditableRoot : BusinessBase<EditableRoot>
{
#region Business Methods
public static readonly PropertyInfo<EditableChild> Email1Property =
RegisterProperty<EditableChild>(c => c.Email1);
public static readonly PropertyInfo<EditableChild> Email2Property =
RegisterProperty<EditableChild>(c => c.Email2);
public EditableChild Email1
{
get { return GetProperty(Email1Property); }
private set { LoadProperty(Email1Property, value); }
}
public EditableChild Email2
{
get { return GetProperty(Email2Property); }
private set { LoadProperty(Email2Property, value); }
}
#endregion
#region Business Rules
protected override void OnChildChanged(ChildChangedEventArgs e)
{
if (e.ChildObject is EditableChild && e.PropertyChangedArgs.PropertyName == "EmailAddress")
{
Email1.CheckEmailRules();
Email2.CheckEmailRules();
}
base.OnChildChanged(e);
}
#endregion
#region Factory Methods
private EditableRoot()
{
/* Require use of factory methods */
}
public static EditableRoot New()
{
return DataPortal.Create<EditableRoot>();
}
#endregion
#region Data Access
[RunLocal]
protected override void DataPortal_Create()
{
using (BypassPropertyChecks)
{
Email1 = EditableChild.New();
Email2 = EditableChild.New();
}
base.DataPortal_Create();
}
#endregion
}
[Serializable]
public class EditableChild : BusinessBase<EditableChild>
{
#region Business Methods
public static readonly PropertyInfo<string> EmailAddressProperty = RegisterProperty<string>(c => c.EmailAddress);
public string EmailAddress
{
get { return GetProperty(EmailAddressProperty); }
set { SetProperty(EmailAddressProperty, value); }
}
#endregion
#region Business Rules
protected override void AddBusinessRules()
{
BusinessRules.AddRule(new DuplicatesRule(EmailAddressProperty));
}
private class DuplicatesRule : BusinessRule
{
public DuplicatesRule(IPropertyInfo primaryProperty)
: base(primaryProperty)
{
InputProperties = new List<IPropertyInfo> { primaryProperty };
}
protected override void Execute(RuleContext context)
{
var address = (string)context.InputPropertyValues[PrimaryProperty];
if (string.IsNullOrEmpty(address)) return;
var target = (EditableChild) context.Target;
var parent = (EditableRoot) target.Parent;
var email1 = (EditableChild)ReadProperty(parent, EditableRoot.Email1Property);
var email2 = (EditableChild)ReadProperty(parent, EditableRoot.Email2Property);
var addresses = new List<string>();
if (!string.IsNullOrEmpty(email1.EmailAddress)) addresses.Add(email1.EmailAddress);
if (!string.IsNullOrEmpty(email2.EmailAddress)) addresses.Add(email2.EmailAddress);
if (addresses.Count() > addresses.Distinct(StringComparer.OrdinalIgnoreCase).Count())
{
context.AddErrorResult("Duplicate email address not allowed.");
}
}
}
internal void CheckEmailRules()
{
BusinessRules.CheckRules(EmailAddressProperty);
}
#endregion
#region Factory Methods
private EditableChild()
{
/* Require use of factory methods */
}
internal static EditableChild New()
{
return DataPortal.CreateChild<EditableChild>();
}
#endregion
}