CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Forum has moved

New location: CSLA .NET forum


CSLA .NET Resources:
  • CSLA .NET forum
  • CSLA .NET home page
  • Some doubt of Business Rule

    rated by 0 users
    Answered (Verified) This post has 1 verified answer | 11 Replies | 1 Follower

    Not Ranked
    8 Posts
    Sam_Lin posted on Tue, May 28 2013 12:04 PM

    Dear All:

               I am a junior in CSLA framework. There's a doubt when i reading the "Using CSLA 4" about the business rule: It says "the target property can only be used on the ui thread and any use of this property on a background thread will lead to cross-thread exceptions or nasty threading bugs"

    My doubt:

    1. this rule is only suitable for async rule or both sync/async rule?

    2.if i don't have the ui thread, and it just a service to expose interface to others,in this case, can i use the target ?

    3. Dose everyone could illustrate some detail example to explain what problem will occur when use target in background thread?

    Thanks.

    Answered (Verified) Verified Answer

    Top 10 Contributor
    2,279 Posts
    Verified by Sam_Lin

    Hi,

    Typically - rules is triggered by a user editing a property in the UI. So it is likely that the rules Execute method will be called on the UI thread on an object that is databound. You will get cross thread exception when you try to set properties on an object in a background thread (actually when the OnPropertyChanged event is called and there is eventlisteners on another thread).

    When rules have IsAsync = true this tells the RuleEngine to not call context.Complete automatically. It is then your code´s responsibility to call context.Complete when the async operation is completed. 

    When you use ASP.NET or WCF you will typically load data into the object and call BusinessRules.CheckRules(). This is more efficient than calling rules on every property setter.

    So your rules may be sync or async. Async rules may only get the contextTarget when ProvideTargetWhenAsync = true and you explicitly take reposibility for interaction with context.Target. 

    What is the rule expected to do?

    Jonny Bekkum, Norway CslaContrib Coordinator

    All Replies

    Top 10 Contributor
    2,279 Posts
    Verified by Sam_Lin

    Hi,

    Typically - rules is triggered by a user editing a property in the UI. So it is likely that the rules Execute method will be called on the UI thread on an object that is databound. You will get cross thread exception when you try to set properties on an object in a background thread (actually when the OnPropertyChanged event is called and there is eventlisteners on another thread).

    When rules have IsAsync = true this tells the RuleEngine to not call context.Complete automatically. It is then your code´s responsibility to call context.Complete when the async operation is completed. 

    When you use ASP.NET or WCF you will typically load data into the object and call BusinessRules.CheckRules(). This is more efficient than calling rules on every property setter.

    So your rules may be sync or async. Async rules may only get the contextTarget when ProvideTargetWhenAsync = true and you explicitly take reposibility for interaction with context.Target. 

    What is the rule expected to do?

    Jonny Bekkum, Norway CslaContrib Coordinator

    Not Ranked
    8 Posts

    Thanks, JonnyBee

          i think i can descripe this rule as below:

                 Target(BusinessBase) is not thread safety, There will be a problem when multi-thread access the target and its properties

                That's mean when i guarantee the target is thread safety, there won't be a problem.

    Right?

    Top 10 Contributor
    2,279 Posts

    Hio,

    Most of .NET framework is NOT thread safe so I'm afraid I do not quite understand how you can make target thread safe.

    For CSLA part it is mostly UI Events that causes problems when they occur from a thred that is NOT the UI Thread.
    This will cause cross-thread exception to be thrown.

    I stil do not understand what the purpose of the rule is.

    Jonny Bekkum, Norway CslaContrib Coordinator

    Not Ranked
    8 Posts
    Sam_Lin replied on Thu, May 30 2013 10:39 AM

    OK, don't worry about that. It just the way of my understanding(i don't want to bring the UI/Background thread to it) . Maybe it's very hard to make the target thread safe.

    So, my understanding is right?

     

    Thanks Jonney.

    Top 100 Contributor
    80 Posts

    Here is an example of running a rule both on the current UI thread and using an async call on another thread.  The UI thread just checks to see that the name isn't empty.  Then a command is called to check the database that the name is unique and doesn't duplicate another name in the database:

        using Csla.Core;

        using Csla.Rules;

     

        /// <summary>

        /// The group validate name rule.

        /// </summary>

        public class GroupGroupValidateNameRule : BusinessRule

        {

            public GroupGroupValidateNameRule(IPropertyInfo primaryProperty)

                : base(primaryProperty)

            {

                ProvideTargetWhenAsync = true;

                IsAsync = true;

     

                AffectedProperties.Add(GroupGroupItem.NameProperty);

            }

           

            protected override void Execute(RuleContext context)

            {

                GroupGroupItem target = (GroupGroupItem)context.Target;

                if (target.Name == string.Empty)

                {

                    context.AddErrorResult("Group Name Cannot Be Empty.");

                    context.Complete();

                }

                else

                {

                    // Check for duplicated name

                    GroupGroupValidateNameCommand.BeginExecute(target.Name, target.Id, (o, e) =>

                    {

                        if (e.Error != null)

                        {

                            throw e.Error;

                        }

                        else

                        {

                            if (e.Object.Duplicate)

                            {

                                context.AddErrorResult("Group Name Is Already In Use.  Please Choose Another Name.");

                                context.Complete();

                            }

                            else

                            {

                                context.AddSuccessResult(true);

                                context.Complete();

                            }

                        }

                    });               

                }

            }

        }

     

    Hope this will help find what you are looking for.

    Todd

    Top 10 Contributor
    2,279 Posts

    Hi Todd, 

    Your rule is not correct. You MUST make sure to always call context.Complete in the callback - or else the object/property will remain "busy" and you will not get the ValidationCompleted event. 

    So - you should not throw the exception - rather add the error message as AddErrorMessage and call context.Complete().

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 100 Contributor
    80 Posts

    Thanks, Jonny.  One of the boiler-plate cut and paste things... Here is a new copy:

        using Csla.Core;

        using Csla.Rules;

     

        /// <summary>

        /// The group group validate name rule.

        /// </summary>

        public class GroupGroupValidateNameRule : BusinessRule

        {

            public GroupGroupValidateNameRule(IPropertyInfo primaryProperty)

                : base(primaryProperty)

            {

                ProvideTargetWhenAsync = true;

                IsAsync = true;

     

                AffectedProperties.Add(GroupGroupItem.NameProperty);

            }

           

            protected override void Execute(RuleContext context)

            {

                GroupGroupItem target = (GroupGroupItem)context.Target;

                if (target.Name == string.Empty)

                {

                    context.AddErrorResult("Group Name Cannot Be Empty.");

                    context.Complete();

                }

                else

                {

                    // Check for duplicated name

                    GroupGroupValidateNameCommand.BeginExecute(target.Name, target.Id, (o, e) =>

                    {

                        if (e.Error != null)

                        {

                            context.AddErrorResult(e.Error.Message);

                            context.Complete();

                        }

                        else

                        {

                            if (e.Object.Duplicate)

                            {

                                context.AddErrorResult("Group Name Is Already In Use.  Please Choose Another Name.");

                                context.Complete();

                            }

                            else

                            {

                                context.AddSuccessResult(true);

                                context.Complete();

                            }

                        }

                    });               

                }

            }

        }

     

    Todd

    Not Ranked
    8 Posts

    If i change properties of target in the call back method, It will be a problem? If there's no other thread access the target such as "OnPropertiesChanged",it will still be a problem ?

    Top 10 Contributor
    2,279 Posts

    Hi

    My general recommendation is to NEVER set an objects properties directly by the property setter in a rule Execute method. This will trigger the rule engine to run from within another rule execute method and may cause infinite loops. 

    In order to update property values on an object you may use 

    • context.AddOutValue or
    • <rule>.LoadProperty (similar to object factories)

    and make sure that all properties to be updated is added to AffectedProperties list in the constructor method of the rule.

    The rule engine will then run rules for the affected properties and call OnPropertyChanged for you. 

    Jonny Bekkum, Norway CslaContrib Coordinator

    Not Ranked
    8 Posts

    Thanks.

    Top 100 Contributor
    80 Posts

    Sam Lin,

    Here is an example of setting properties in a rule:

        class DataEntrySetIssueItemSlaRule : BusinessRule

        {

            public DataEntrySetIssueItemSlaRule(IPropertyInfo primaryProperty)

                : base(primaryProperty)

            {

                InputProperties = new List<IPropertyInfo> { PrimaryProperty };

     

                AffectedProperties.Add(DataEntryIssueItem.SlaDueByProperty);

                AffectedProperties.Add(DataEntryIssueItem.ShowSlaProperty);

            }

     

            protected override void Execute(RuleContext context)

            {

     

                var target = (DataEntryIssueItem)context.Target;

                if (target.CustomerStdHrs > TimeSpan.Zero || target.CustomerCrtHrs > TimeSpan.Zero)

                {

                    DateTime? slaDate = null;

     

                    // Critical Part and Critical Problem gets Critical Hrs

                    if (target.PartCritical && target.Problem.Critical && target.CustomerCrtHrs > TimeSpan.Zero)

                    {

                        // Calculate SLA date

                        slaDate = target.CalendarEventList.CalculateDate(target.Added, target.CustomerCrtHrs);

                    }

                    else

                    {

                        if (target.CustomerStdHrs > TimeSpan.Zero)

                        {

                            slaDate = target.CalendarEventList.CalculateDate(target.Added, target.CustomerStdHrs);

                        }

                    }

                    context.AddOutValue(DataEntryIssueItem.SlaDueByProperty, slaDate);

                    context.AddOutValue(DataEntryIssueItem.ShowSlaProperty, slaDate != null);

                    context.Complete();

                }

            }

        }

     

    Todd

    Page 1 of 1 (12 items) | RSS

    Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
    Email admin@lhotka.net for support.
    Powered by Community Server (Non-Commercial Edition), by Telligent Systems