AsyncRuleHandler signature - feedback solicitation

AsyncRuleHandler signature - feedback solicitation

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


justncase80 posted on Monday, July 14, 2008

Hello everyone!

   I am currently working with Rocky on CslaLight and I am working on implementing the ability to have async validation rules. Currently it is mostly working with only a few details left to flesh out. One of these details is the signature of the AsyncRuleHandler delegate.

   To do things asynchronously we have found that we needed to split the argument parameter into an object specifically for "inargs" and one for "outargs". There is also a delegate passed into the method that needs to be called when your asynchronous operation completes successfully. An example implementation of this method might be:
private static void Rule1(
object target,
AsyncRuleArgs inargs,
AsyncRuleResult outargs,
AsyncRuleResultHandler result)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
string propertyName = inargs.PropertyName;
object foo = ((Rule1Args)inargs).Foo; // use custom rule args

// some asyncrhonous work will be done...
e.Result = true;
};
worker.RunWorkerCompleted += (s, e) =>
{
outargs.Result = (bool)e.Result;
result(outargs);
};

// simulating an asynchronous process.
worker.RunWorkerAsync();
}
This is interesting because an "outargs" object is passed into the method with defaults such as Severity, Description, PropertyName, etc. But it is also passed back into the result delegate and handled by the broken rules collection.

There is one alternative to this approach that is, technically, equivalent but is somewhat different stylistically. What I would like to do is show you the alternate scheme and solicit feedback on which of the two is superior and, perhaps, if there is a better scheme that anyone can come up with while still being technically feasible.

The other approach is to add the inargs and the result handler as members of outargs so your handler might look more like this:
private static void Rule1(
object target,
AsyncRuleResult r)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
string propertyName = r.Args.PropertyName;
object foo = ((Rule1Args)r.Args).Foo; // use custom rule args

// some asyncrhonous work will be done...
e.Result = true;
};
worker.RunWorkerCompleted += (s, e) =>
{
r.Result ( (bool)e.Result ); // the delegate is on args
};

// simulating an asynchronous process.
worker.RunWorkerAsync();
}
So the question really is, what is more intuitive? What would you prefer to see? Is it intuitive enough to have a method on the incoming argument that must be called, or is it more clear to have it as it's own parameter? Should the incoming arguments be associated with the result object, or is it more clear to be a seperate parameter? What is better, simplicity or being explicit?


RockfordLhotka replied on Tuesday, July 15, 2008

Another option might be to have a method on the args to do the callback in an even more abstract manner:

r.Complete(true);

So really there are at least three options:

  1. callback(outargs); // call delegate directly; delegate is an argument
  2. args.Result(true); // call delegate directly, delegate exposed from args
  3. args.Complete(true); // call method that calls delegate behind the scenes

I kind of lean toward option 3 because it totally hides the delegate and potentially provides the best abstraction.

But we've posted this thread to solicit input from others in the community, so chime in if you have an opinion - otherwise you'll have to live with our choice :)

RockfordLhotka replied on Tuesday, July 15, 2008

I guess some more context might be in order - come to think of it.

In Silverlight all server communication is asynchronous. That's just the way it is.

So CSLA Light has an asynchronous data portal. Instead of Fetch(), there's BeginFetch() with an asynchronous callback that occurs when the operation is complete.

To keep parity, CSLA .NET 3.6 also has an asynchronous data portal - as an option. It has the same API as the CSLA Light version. That's pretty cool by itself imo :)

Sometimes you write a validation rule that has to talk to the server. Perhaps an Exists() check that runs a stored procedure via a Command object or something like that. This is not uncommmon.

Since the data portal is async, this means that the validation rule must be async too!!

That's a problem, because the validation rules subsystem is all synchronous now. So Justin has put a lot of work into enabling async rules alongside the sync rules.

The end result is that you can either write a sync rule like today, or an async rule. If you write an async rule, then in the callback you need to tell CSLA Light that the rule is complete - and that's the question here - how do you tell CSLA that the rule is complete (and that it succeeded or failed)?

JoeFallon1 replied on Tuesday, July 15, 2008

I lean towards #3 also.

I prefer to hide as much complexity as possible.

Keep things as simple looking as possible on the surface.

Joe

 

Copyright (c) Marimer LLC