I feel like I'm missing something simple. If you have a BO with Async business rules, how do you wait for the object to no longer be busy before carrying on with something else, such as asking the object to save itself? I would have thought there'd be some method to await the non-busy state, but I can't find anything. A simple
while (bo.IsBusy) { }
doesn't seem to work either (and will burn CPU as well).
Hi,
You have events like BusyChanged or ValidationCompleted that your code can wait for with a EventWaitHandle.
Sorry, I guess I'm not clear on what to do. In an MVC controller if you have an async business rule its possible its still running by the time you get to the action method. I want to make sure that the controller waits for the object to no longer be busy before checking IsValid or calling Save. Can you give an example?
Hi Andy,
I m stuck with this problem as well.
Cf.http://forums.lhotka.net/forums/p/11854/54973.aspx#54973 for another thread on that topic. I did not find a correct implementation yet.
Gilles
Should be as simple as to add this method to your business object:
public async void CheckAllRulesAndWaitForAllRulesToComplete() { var tcs = new TaskCompletionSource<bool>(); // declare event handler EventHandler eh = (sender, e) => tcs.SetResult(true); // attach to validation complete event ValidationComplete += eh; // call check rules BusinessRules.CheckRules(); // wait for tcs to set result (ValidationComplete) await tcs.Task; // unsubscripbe from event ValidationComplete -= eh; }
and call it like this:
root.CheckAllRulesAndWaitForAllRulesToComplete(); if (!root.IsValid) { MessageBox.Show("Object has broken rules and can not be saved"); return; } await root.SaveAsync();
Should be as simple as to add this method to your business object:
public async void CheckAllRulesAndWaitForAllRulesToComplete() { var tcs = new TaskCompletionSource<bool>(); // declare event handler EventHandler eh = (sender, e) => tcs.SetResult(true); // attach to validation complete event ValidationComplete += eh; // call check rules BusinessRules.CheckRules(); // wait for tcs to set result (ValidationComplete) await tcs.Task; // unsubscripbe from event ValidationComplete -= eh; }This is Asp.Net MVC; the rules are run on property set as normal, however since some are async its possible for the BO get to the action method while rules are still running. If there's a way to do this without having the new method call BusinessRules.CheckRules that would work for me.
The most efficient way is to use (or create your own version) of CslaModelBinder.
This use BypassPropertyChecks to load all field values (rather than calling SetProperty and execute rules on a per-property basis) and then call BusinessRules.CheckRules.
You should be able to us the code sample I supplied and just extend it a little with a check for BusinessRules.IsRunningRules or BusinessRules.IsRunningAsyncRules and if so call TaskCompletionSource.SetResult and remove the call to BusinessRules.CheckRules. .
Hi Jonny,
I do not think that the problem is MVC specific.
In my case, we are using a 2 tier - Winform - application. We are doing a mass import.
The import is affecting the firstname & lastname.
I'm updating my business object, by setting the firstname & lastname properties (mordern way, with managed backend field).
As a result, this triggers the async rules.
Thus, when CheckAllRulesAndWaitForAllRulesToComplete() is called, my object is already busy... and is (sometimes) still busy when leaving.
Do you recommend using LoadProperty ? From my point of view, this would break business object encapsulation...
Regards,
Gilles
Hi,
I'd rather look at how the ICheckRules interface is implemented and used in Csla.Web.Mvc.CslaModelBinder. What you need in addition is an overridable method in ICheckRules.CheckRules method and you would be good to go.
You _could_ implement this in your own base classes. I will check with Rocky if we can refactor ICheckRules.CheckRules to call an overridable method.
Copyright (c) Marimer LLC