ValidationComplete, IsBusy, Async Rules

ValidationComplete, IsBusy, Async Rules

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


lacota posted on Sunday, November 16, 2014

I am running into a strange result. I have a business object with async rules. I am running unit tests to test basic crud operations. Update works fine. Insert gives me the Cannot save while IsBusy error. It seems IsBusy remains true even after the ValidationComplete event fires. Any ideas? Here is the code;

var validationCompleteEvent = new ManualResetEvent(false);

var item = MyEntity.New(Guid.NewGuid());

Assert.IsNotNull(item);

item.ValidationComplete += delegate { validationCompleteEvent.Set(); };

item.Name = "Test"; // Triggers the async rule.

validationCompleteEvent.WaitOne(5000,false);

item = item.Save(); // Get error here

ajj3085 replied on Sunday, November 16, 2014

I looked at the documentation for WaitOne, and it doesn't seem to suggest an exception is thrown after the timeout elapses.  So I suspect your rule is never returning (did you forget to call the complete method on the RuleContext?) and the timeout expires, which then continues to the Save call.

lacota replied on Sunday, November 16, 2014

The code for update is virtually identical but works fine. The rules are certainly the same. When I look at the business object prior to save the private field _isBusy is set to false but the public property IsBusy is set to true. The brokenrules collection is empty. If I set a Boolean value in the delegate, it is true.

It seems that the businessrules collection, busyProperties collection is populated but never cleared. I have no unhandled async rule exceptions. What am I missing?

JonnyBee replied on Monday, November 17, 2014

I agree with Andy.

The RuleEngine works in the same way no matter what the status of the object is.

You should be aware tho' that the default DataPortal_Create will call BusinesRules.CheckRules() and probably also trigger the async rule (your async rule is not shown). And the you set the property to trigger the async rule again. I highly recommend that your async property rules inherit from PropertyRule base class. 

You may declare that the async rule is not allowed to run on the "logical serverside" (read DataPortal_XYZ methods). 

Ex: 

public class NameRule : PropertyRule
{
    public NameRule(IPropertyInfo primaryProperty) : base(primaryProperty)
    {
        IsAsync = true;
        CanRunOnServer = false;
        CanRunAsAffectedProperty = false;
        CanRunInCheckRules = false;
    }

From my own experience i always try to make my async rules only run when the actual property is modified by the end user.

I typically use async rules only for rules that would lock the UI - so (to me) it makes sense to not allow async rules to run on the data access side, as an affected property or in CheckRules.  AffectedProperties is the second pass in the RuleEngine where the Name (here) may have been updated from another rule.

Did you verify that you actually got a ValidationCompleted event? 

If you could post a complete solution then we could give you a more precise feedback.

lacota replied on Thursday, November 20, 2014

I have confirmed that the ValidationComplete event is firing after I change the property. But despite the event firing, the businessobject IsBusy. When I inspect the object the _busyProperties collection contains my two properties with async rules. I have the same settings.

lacota replied on Monday, December 01, 2014

I found the problem:

First I need to set a flag in the delegate to capture if the object IsValid;

Second, I need to Reset and WaitOne after every property with an async rule.

item.ValidationComplete += delegate {

eventRaised = true;

isValid = item.IsValid;

validationCompleteEvent.Set();

};

item.Code = data.Payload.Code;

validationCompleteEvent.WaitOne(10000, false);

Copyright (c) Marimer LLC