DataPortal.Create failed Exception (User.IsBusy == true) with asynchronous rule

DataPortal.Create failed Exception (User.IsBusy == true) with asynchronous rule

Old forum URL: forums.lhotka.net/forums/t/12180.aspx


mightymiracleman posted on Friday, October 11, 2013

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!

 

g.beraudo@castsoftware.com replied on Friday, October 11, 2013

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

g.beraudo@castsoftware.com replied on Friday, October 11, 2013

Take a look to: http://forums.lhotka.net/forums/p/11850/54935.aspx

mightymiracleman replied on Tuesday, October 15, 2013

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!

JonnyBee replied on Tuesday, October 15, 2013

mightymiracleman

   [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