Wait for object to no longer be busy?

Wait for object to no longer be busy?

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


ajj3085 posted on Tuesday, September 10, 2013

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).

JonnyBee replied on Tuesday, September 10, 2013

Hi,

You have events like BusyChanged or ValidationCompleted that your code can wait for with a EventWaitHandle.

ajj3085 replied on Tuesday, November 19, 2013

JonnyBee
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?

g.beraudo@castsoftware.com replied on Tuesday, November 19, 2013

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

JonnyBee replied on Wednesday, November 20, 2013

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();

ajj3085 replied on Wednesday, November 20, 2013

JonnyBee

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();

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.

JonnyBee replied on Wednesday, November 20, 2013

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. . 

g.beraudo@castsoftware.com replied on Friday, November 22, 2013

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

JonnyBee replied on Sunday, November 24, 2013

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