I'm using CSLA 4.5 (4.5.30.0)
I want to use an asynchronous rule to check for duplicate users, I'm not sure why this is happening, sometimes this works just fine, and other times I get the following exception:
==================================================================
Result Message:
Test method EMP.Tests.UserTest.CreateAdminUserForCompany threw exception:
Csla.DataPortalException: DataPortal.Create failed (User.IsBusy == true) ---> System.InvalidOperationException: User.IsBusy == true
Result StackTrace:
at Csla.Server.SimpleDataPortal.<Create>d__0.MoveNext()
--- End of inner exception stack trace ---
at Csla.Server.SimpleDataPortal.<Create>d__0.MoveNext()
at Csla.DataPortal`1.Create(Type objectType, Object criteria)
at Csla.DataPortal`1.Create(Object criteria)
at Csla.DataPortal.Create[T](Object criteria)
at Csla.DataPortal.Create[T]()
at EMP.BusinessObjects.Administration.User.NewUser() in c:\Users\tom.luther\Dropbox\EquipmentMaintenance\EMP.BusinessObjects\Administration\User.cs:line 302
at EMP.Tests.UserTest.CreateAdminUserForCompany() in c:\Users\tom.luther\Dropbox\EquipmentMaintenance\EMP\EMP.Tests\UserTest.cs:line 76
==================================================================
I have a feeling I'm not doing something right with the rule, or perhaps the dataportal.
Business Object DataPortal_Create Method:
[RunLocal]
protected override void DataPortal_Create()
{
base.DataPortal_Create();
LoadProperty(UserIdProperty, --_userCount);
}
BusinessRule (Contained in Business Object):
private class UsernameDoesNotExist : Csla.Rules.BusinessRule
{
public UsernameDoesNotExist(IPropertyInfo primaryProperty)
: base(primaryProperty)
{
IsAsync = true;
ProvideTargetWhenAsync = true;
}
protected async override void Execute(RuleContext context)
{
var usr = context.Target as User;
if (usr != null && usr.IsNew)
{
DuplicateUserChecker chk = new DuplicateUserChecker();
chk._username = usr.Username;
chk = await DataPortal.ExecuteAsync(chk);
if (chk._usernameExists)
{
context.AddErrorResult(string.Format("Username '{0}' exists, please choose a different username", usr.Username));
}
}
context.Complete();
}
[Serializable]
private class DuplicateUserChecker : CommandBase<DuplicateUserChecker>
{
public string _username = string.Empty;
public bool _usernameExists;
protected new async Task DataPortal_Execute()
{
await Task.Run(() =>
{
using (IDbConnection cn = EMPUtils.GetConnection())
{
cn.Open();
using (IDbCommand cmd = cn.CreateCommand())
{
cmd.CommandText = "pr_emp_UsernameChecker_Execute";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(EMPUtils.GetParameter("@sUsername", _username));
_usernameExists = (bool)cmd.ExecuteScalar();
}
cn.Close();
}
});
}
}
}
Addition of the Rule int he "AddBusinessRules" method:
BusinessRules.AddRule(new UsernameDoesNotExist(UsernameProperty));
Any ideas out there? Thank you!
Hi,
Please check the rule samples provided in Csla zip file.
It indicates that you should disable async rule on the server side: you can t ensure that the async will complete before returning the object to the client. In that case a 'busy' object would be returned to the the client.
I do not remember the exact properties to set in the rule constructor, this is detailed in the doc shipped with the samples.
Gilles
Take a look to: http://forums.lhotka.net/forums/p/11850/54935.aspx
Thank you!
I added the following RunMode to the rule constructor:
public UsernameDoesNotExist(IPropertyInfo primaryProperty)
: base(primaryProperty)
{
IsAsync = true;
ProvideTargetWhenAsync = true;
RunMode = RunModes.DenyOnServerSidePortal;
}
I haven't had the issue since!
[RunLocal]
protected override void DataPortal_Create()
{
base.DataPortal_Create();
LoadProperty(UserIdProperty, --_userCount);
}
You should also be aware that base.DataPortal_Create() is just this code and should be called AFTER initial property values has been set.
[RunLocal] protected virtual void DataPortal_Create() { BusinessRules.CheckRules(); }
Copyright (c) Marimer LLC