New async validation rules - Possible Problem???New async validation rules - Possible Problem???
Old forum URL: forums.lhotka.net/forums/t/5872.aspx
vdhant posted on Monday, November 24, 2008
I have been playing around a little with the async validation rules and have noticed a little bit of a problem.
If "void CheckRules(List<IRuleMethod> list)" throws an exception, in the catch statement it calls "rule.RuleArgs.PropertyName". Before the async validation rules came along this would have been fine. But in the case where async validation rule throws an exception, AsyncRuleMethod throws an exception when RuleArgs is called.
catch (Exception ex)
{
//Throw a more detailed exception
throw new ValidationException(string.Format(Resources.ValidationRulesException, rule.RuleArgs.PropertyName, rule.RuleName), ex);
}
internal class AsyncRuleMethod ... {
....
RuleArgs IRuleMethod.RuleArgs
{
get { throw new NotSupportedException(); }
}
....
}
cheers
Anthony
RockfordLhotka replied on Monday, November 24, 2008
I don't believe this is a bug. This is by design.
An async rule method can never allow an unhandled exception to occur. Ever.
Async rule methods must always catch all exceptions and must return them through the parameter provided in the callback.
This is because an async rule method is running on a background thread (or may be) and so an unhandled exception would then flow up to the .NET runtime as an unhandled exception - and that's a problem.
So we have a scheme by which an exception in the async rule method can be safely returned to CSLA, which can then take care of it on the primary thread. But never in the CheckRules() method - because that merely starts the async rule and never handles any result.
Of course you may fully understand this already - in which case I'm misunderstanding you, and I need more clarification.
vdhant replied on Tuesday, November 25, 2008
Hi
Rocky thanks for the reply...
I wasn't pointing out the need to catch the exception and then re-throw it, i
totally get that.
I was trying to point out the face that the "rule.RuleArgs.PropertyName" part in the catch
statement causes a NotSupportedException to occur when using a rule that
caused the error is of type AsyncRuleMethod (which is the case when dealing
with Async rules).
In other words given the catch statements in CheckRules, I would expect that
this catch statement be run if an error occurs whilst processing the validation
rule. Next I would expect that the catch statement would throw a new exception
of type ValidationException which contains whatever the original exception was.
In the case where the rule that fails is of type RuleMethod, this works
fine....
But In the case where rule of type AsyncRuleMethod when following code is
executed "throw new
ValidationException(string.Format(Resources.ValidationRulesException, rule.RuleArgs.PropertyName,
rule.RuleName), ex);" the bolded part thow a NotSupportedException excecption
which contains no information about the original exception. The reason why this
occurs is because AsyncRuleMethod exsplicity implements the RuleArgs property
and throws a NotSupportedException exception if it is ever called.
When this occurs the application gets back a NotSupportedException exception
which has nothing to do with the error that occurred in the first place and not
what of finding out how the original exception occurred.
I hope that makes a bit more sense.
Cheers
Anthony RockfordLhotka replied on Tuesday, November 25, 2008
I am still not sure there’s an issue.
CheckRules() doesn’t execute async rules. It merely starts
the rule. The rule method can’t fail – async rule methods must never
throw an exception – so that catch block should never be hit.
Rocky
vdhant replied on Tuesday, November 25, 2008
Hi Rocky
You have just said that the CheckRules method doesn't execute async rules and that it only states/finds the async rules... I'm sorry but I may be way off the mark but I thought that the following section of code was executing any found async rules within the CheckRules method (note the bolded invoke)...
private void CheckRules(List<IRuleMethod> list)
{
....
IAsyncRuleMethod[] asyncRules = null;
lock (SyncRoot)
asyncRules = ValidatingRules.ToArray();
// They must all be added to the ValidatingRules list before you can invoke them.
// Otherwise you have a race condition, where if a rule completes before the next one is invoked
// then you may have the ValidationComplete event fire multiple times invalidly.
foreach (IAsyncRuleMethod rule in asyncRules)
{
try
{
rule.Invoke(_target, asyncRule_Complete);
}
catch (Exception ex)
{
// throw a more detailed exception
throw new ValidationException(
string.Format(Properties.Resources.ValidationRulesException, rule.RuleArgs.PropertyName,
rule.RuleName), ex);
}
}
}
Also please note that the problem that I have been trying to raise is about the catch statement that surrounds this invoke, the other catch statement within CheckRules should be fine as you have pointed out, but I can't see how this one can be ok.
If any errors occur within method that is invoked (and doesn't happen on a different thread... i.e. the rule that has been executed hasn't spun up a new thread yet), the problem that I have described will occur.
Hope this helps and for the record I may have total missed something that is going on here so just let me know if I’m off the mark and I will leave it, but at the moment I can't how the second catch statement can't be an issue, because it exists only to catch exception generated by the invoke of the rules that are of type async.
Cheers
Anthony
RockfordLhotka replied on Wednesday, November 26, 2008
It is a bit confusing when you look at the code.
But the rule is very strict: an async rule method may never
throw an exception.
So yes, CheckRules() “runs” the async method. But really the
idea is that the async method does its work on a background thread. It shouldn’t
do anything on the calling thread, so there really shouldn’t be anything to
actually fail back into CheckRules(). Any failure should occur in the rule
processing on the background thread, and that exception should be returned
through the callback.
If you somehow do create an async method that does work on the
calling thread that could fail, there are two things to consider. First, it isn’t
async yet, so this is synchronous code. Second, it should still never
allow an unhandled exception (see the rule), and so any failure should cause
the exception to be returned via the callback.
The whole async rule infrastructure is based on the rule that an
async method may never throw an exception. That any exception, in any part of
the rule, is returned via the callback. That every rule has a callback, whether
it failed or not.
This affects exception handling, but also the IsBusy property
and related processing.
Rocky
vdhant replied on Wednesday, November 26, 2008
Cool thanks for that... I only have one question then, why have the try catch block around the async code, if 1) its never going to be used and 2) if it does get called somehow, the catch block fails because of the problem that I have described? I would think that if you are going to have a try/catch block the last thing you would want is the catch to throw a new exception as its throwing exception, regardless of whether it "should" be called. My problem is not whether the try/catch should or shouldn't be there but the fact that if it is going to be there, but the fact that the catch is not going to work as intended if it happened to run.
Cheers
Anthony
RockfordLhotka replied on Wednesday, November 26, 2008
I think you are right in that in that regard it is a bug –
and I’ll put it on the list.
Thanks!!
Rocky
From: vdhant
[mailto:cslanet@lhotka.net]
Sent: Wednesday, November 26, 2008 1:57 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: New async validation rules - Possible
Problem???
Cool thanks for that... I only have one question then, why
have the try catch block around the async code, if 1) its never going to be
used and 2) if it does get called somehow, the catch block fails because of the
problem that I have described? I would think that if you are going to have a
try/catch block the last thing you would want is the catch to throw a new
exception as its throwing exception, regardless of whether it
"should" be called. My problem is not whether the try/catch should or
shouldn't be there but the fact that if it is going to be there, but the fact
that the catch is not going to work as intended if it happened to run.
Cheers
Anthony
vdhant replied on Wednesday, November 26, 2008
No problem, just glad i could help
RockfordLhotka replied on Wednesday, December 03, 2008
My proposed solution to this problem is to have AsyncRuleMethod.RuleArgs return a valid value
RuleArgs IRuleMethod.RuleArgs
{
get { return new RuleArgs(_args.Properties[0].Name); }
}
This shouldn't really happen (as discussed earlier in this thread), but if someone does mess up and allow an unhandled exception to flow out of an async rule method, at least the result is predictable.
Does that seem reasonable to you?
Copyright (c) Marimer LLC