diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs index dade0c85..0f0db9d1 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs @@ -1,390 +1,405 @@ -#region License - -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -using System; -using System.Collections; -using System.Reflection; -using AopAlliance.Intercept; -using Common.Logging; - -namespace Spring.Aspects.Exceptions -{ - /// - /// Exception advice to perform exception translation, conversion of exceptions to default return values, and - /// exception swallowing. Configuration is via a DSL like string for ease of use in common cases as well as - /// allowing for custom translation logic by leveraging the Spring expression language. - /// - /// - /// - /// The exception handler collection can be filled with either instances of objects that implement the interface - /// or a string that follows a simple syntax for most common exception management - /// needs. The source exceptions to perform processing on are listed immediately after the keyword 'on' and can - /// be comma delmited. Following that is the action to perform, either log, translate, wrap, replace, return, or - /// swallow. Following the action is a Spring expression language (SpEL) fragment that is used to either create the - /// translated/wrapped/replaced exception or specify an alternative return value. The variables available to be - /// used in the expression language fragment are, #method, #args, #target, and #e which are 1) the method that - /// threw the exception, the arguments to the method, the target object itself, and the exception that was thrown. - /// Using SpEL gives you great flexibility in creating a translation of an exception that has access to the calling context. - /// - /// Common translation cases, wrap and rethrow, are supported with a shorter syntax where you can specify only - /// the exception text for the new translated exception. If you ommit the exception text a default value will be - /// used. - /// The exceptionsHandlers are compared to the thrown exception in the order they are listed. logging - /// an exception will continue the evaluation process, in all other cases exceution stops at that point and the - /// appropriate exceptions handler is executed. - /// - /// - /// - /// on FooException1 log 'My Message, Method Name ' + #method.Name - /// on FooException1 translate new BarException('My Message, Method Called = ' + #method.Name", #e) - /// on FooException2,Foo3Exception wrap BarException 'My Bar Message' - /// on FooException4 replace BarException 'My Bar Message' - /// on FooException5 return 32 - /// on FooException6 swallow - /// - /// - /// - /// - /// - /// - /// Mark Pollack - public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice - { - #region Fields - - private static readonly ILog log = LogManager.GetLogger(typeof(ExceptionHandlerAdvice)); - - private IList exceptionHandlers = new ArrayList(); - - private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$"; - - private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$"; - - #endregion - - #region Properties - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions. - /// - /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions. - public override string OnExceptionNameRegex - { - get { return onExceptionNameRegex; } - set { onExceptionNameRegex = value; } - } - - /// - /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. - /// - /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. - public override string OnExceptionRegex - { - get { return onExceptionRegex; } - set { onExceptionRegex = value; } - } - - /// - /// Gets or sets the exception handler. - /// - /// The exception handler. - public IList ExceptionHandlers - { - get { return exceptionHandlers; } - set { exceptionHandlers = value; } - } - - #endregion - - #region IMethodInterceptor implementation - - /// - /// Implement this method to perform extra treatments before and after - /// the call to the supplied . - /// - /// - ///

- /// Polite implementations would certainly like to invoke - /// . - ///

- ///
- /// - /// The method invocation that is being intercepted. - /// - /// - /// The result of the call to the - /// method of - /// the supplied ; this return value may - /// well have been intercepted by the interceptor. - /// - /// - /// If any of the interceptors in the chain or the target object itself - /// throws an exception. - /// - public override object Invoke(IMethodInvocation invocation) - { - try - { - return invocation.Proceed(); - } - catch (TargetInvocationException ex) - { - Exception realException = ex.InnerException; - InvokeHandlers(realException, invocation); - throw realException; - } - catch (Exception ex) - { - object returnVal = InvokeHandlers(ex, invocation); - - if (returnVal == null) - { - return null; - } - - // if only logged - if (returnVal.Equals("logged")) - { - throw; - } - - //only here if we only are swallowing, returning alternative value, no matching handler was found. - - // no matching handler. - if (returnVal.Equals("nomatch")) - { - throw; - } - else - { - //TODO make spring specific value. - if (!returnVal.Equals("swallow")) - { - return returnVal; - } - else - { - return null; - } - } - } - } - - #endregion - - #region IInitializingObject implementation - - /// - /// Invoked by an - /// after it has injected all of an object's dependencies. - /// - /// - ///

- /// This method allows the object instance to perform the kind of - /// initialization only possible when all of it's dependencies have - /// been injected (set), and to throw an appropriate exception in the - /// event of misconfiguration. - ///

- ///

- /// Please do consult the class level documentation for the - /// interface for a - /// description of exactly when this method is invoked. In - /// particular, it is worth noting that the - /// - /// and - /// callbacks will have been invoked prior to this method being - /// called. - ///

- ///
- /// - /// In the event of misconfiguration (such as the failure to set a - /// required property) or if initialization fails. - /// - public override void AfterPropertiesSet() - { - if (exceptionHandlers.Count == 0) - { - throw new ArgumentException("At least one handler is required"); - } - IList newExceptionHandlers = new ArrayList(); - foreach (object o in exceptionHandlers) - { - string handlerString = o as string; - if (handlerString != null) - { - IExceptionHandler handler = Parse(handlerString); - if (handler == null) - { - throw new ArgumentException("Was not able to parse exception handler string [" + handlerString + - "]"); - } - newExceptionHandlers.Add(handler); - } - - } - //TODO sync. - exceptionHandlers = newExceptionHandlers; - } - - #endregion - - #region Methods - - /// - /// Invokes handlers registered for the passed exception and - /// - /// The exception to be handled - /// The that raised this exception. - /// The output of - protected virtual object InvokeHandlers(Exception ex, IMethodInvocation invocation) - { - IDictionary callContextDictionary = new Hashtable(); - callContextDictionary.Add("method", invocation.Method); - callContextDictionary.Add("args", invocation.Arguments); - callContextDictionary.Add("target", invocation.Target); - callContextDictionary.Add("e", ex); - object retValue = "nomatch"; - foreach (IExceptionHandler handler in exceptionHandlers) - { - if (handler != null) - { - if (handler.CanHandleException(ex, callContextDictionary)) - { - retValue = handler.HandleException(callContextDictionary); - if (!handler.ContinueProcessing) - { - return retValue; - } - } - } - } - return retValue; - } - - /// - /// Parses the specified handler string, creating an instance of IExceptionHander. - /// - /// The handler string. - /// an instance of an exception handler or null if was not able to correctly parse - /// handler string. - protected virtual IExceptionHandler Parse(string handlerString) - { - ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(handlerString); - - if (!parsedAdviceExpression.Success) - { - log.Warn("Could not parse exception hander statement " + handlerString); - return null; - } - - return CreateExceptionHandler(parsedAdviceExpression); - } - - private static IExceptionHandler CreateExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) - { - if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0) - { - //TODO support user selection of level, log.Debug , log.Info etc. - LogExceptionHandler handler = new LogExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = "#log.Trace(" + parsedAdviceExpression.ActionExpressionText + ")"; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0) - { - TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0) - { - TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression); - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0) - { - TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression); - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0) - { - SwallowExceptionHandler handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - return handler; - } - else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0) - { - ReturnValueExceptionHandler handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames); - handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; - handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; - return handler; - } - else - { - log.Warn("Could not parse exception hander statement " + parsedAdviceExpression.AdviceExpression); - } - return null; - } - - private static string ParseWrappedExceptionExpression(string action, string handlerString) - { - int endOfActionIndex = handlerString.IndexOf(action) + action.Length; - string exceptionAndMessage = handlerString.Substring(endOfActionIndex).Trim(); - int endOfExceptionTypeIndex = exceptionAndMessage.IndexOf(" "); - - string rawExpressionTextPart; - string exception; - //Has two pieces. - if (endOfExceptionTypeIndex > 0) - { - exception = exceptionAndMessage.Substring(0, endOfExceptionTypeIndex).Trim(); - rawExpressionTextPart = exceptionAndMessage.Substring(endOfExceptionTypeIndex).Trim(); - } - else - { - exception = exceptionAndMessage; - if (action.Equals("wrap")) - { - rawExpressionTextPart = "'Wrapped ' + #e.GetType().Name"; - } else - { - rawExpressionTextPart = "'Replaced ' + #e.GetType().Name"; - } - } - - if (action.Equals("wrap")) - { - return string.Format("new {0}({1}, #e)", exception, rawExpressionTextPart); - } else - { - return string.Format("new {0}({1})", exception, rawExpressionTextPart); - } - } - - - - #endregion - } +#region License + +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using System.Collections; +using System.Reflection; +using AopAlliance.Intercept; +using Common.Logging; + +namespace Spring.Aspects.Exceptions +{ + /// + /// Exception advice to perform exception translation, conversion of exceptions to default return values, and + /// exception swallowing. Configuration is via a DSL like string for ease of use in common cases as well as + /// allowing for custom translation logic by leveraging the Spring expression language. + /// + /// + /// + /// The exception handler collection can be filled with either instances of objects that implement the interface + /// or a string that follows a simple syntax for most common exception management + /// needs. The source exceptions to perform processing on are listed immediately after the keyword 'on' and can + /// be comma delmited. Following that is the action to perform, either log, translate, wrap, replace, return, or + /// swallow. Following the action is a Spring expression language (SpEL) fragment that is used to either create the + /// translated/wrapped/replaced exception or specify an alternative return value. The variables available to be + /// used in the expression language fragment are, #method, #args, #target, and #e which are 1) the method that + /// threw the exception, the arguments to the method, the target object itself, and the exception that was thrown. + /// Using SpEL gives you great flexibility in creating a translation of an exception that has access to the calling context. + /// + /// Common translation cases, wrap and rethrow, are supported with a shorter syntax where you can specify only + /// the exception text for the new translated exception. If you ommit the exception text a default value will be + /// used. + /// The exceptionsHandlers are compared to the thrown exception in the order they are listed. logging + /// an exception will continue the evaluation process, in all other cases exceution stops at that point and the + /// appropriate exceptions handler is executed. + /// + /// + /// + /// on FooException1 log 'My Message, Method Name ' + #method.Name + /// on FooException1 translate new BarException('My Message, Method Called = ' + #method.Name", #e) + /// on FooException2,Foo3Exception wrap BarException 'My Bar Message' + /// on FooException4 replace BarException 'My Bar Message' + /// on FooException5 return 32 + /// on FooException6 swallow + /// + /// + /// + /// + /// + /// + /// Mark Pollack + public class ExceptionHandlerAdvice : AbstractExceptionHandlerAdvice + { + #region Fields + + /// + /// Log instance available to subclasses + /// + protected static readonly ILog log = LogManager.GetLogger(typeof(ExceptionHandlerAdvice)); + + private IList exceptionHandlers = new ArrayList(); + + private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$"; + + private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$"; + + #endregion + + #region Properties + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception name' and exception handling actions. + /// + /// The regex string to parse advice expressions starting with 'on exception name' and exception handling actions. + public override string OnExceptionNameRegex + { + get { return onExceptionNameRegex; } + set { onExceptionNameRegex = value; } + } + + /// + /// Gets or sets the Regex string used to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. + /// + /// The regex string to parse advice expressions starting with 'on exception (constraint)' and exception handling actions. + public override string OnExceptionRegex + { + get { return onExceptionRegex; } + set { onExceptionRegex = value; } + } + + /// + /// Gets or sets the exception handler. + /// + /// The exception handler. + public IList ExceptionHandlers + { + get { return exceptionHandlers; } + set { exceptionHandlers = value; } + } + + #endregion + + #region IMethodInterceptor implementation + + /// + /// Implement this method to perform extra treatments before and after + /// the call to the supplied . + /// + /// + ///

+ /// Polite implementations would certainly like to invoke + /// . + ///

+ ///
+ /// + /// The method invocation that is being intercepted. + /// + /// + /// The result of the call to the + /// method of + /// the supplied ; this return value may + /// well have been intercepted by the interceptor. + /// + /// + /// If any of the interceptors in the chain or the target object itself + /// throws an exception. + /// + public override object Invoke(IMethodInvocation invocation) + { + try + { + return invocation.Proceed(); + } + catch (TargetInvocationException ex) + { + Exception realException = ex.InnerException; + InvokeHandlers(realException, invocation); + throw realException; + } + catch (Exception ex) + { + object returnVal = InvokeHandlers(ex, invocation); + + if (returnVal == null) + { + return null; + } + + // if only logged + if (returnVal.Equals("logged")) + { + throw; + } + + //only here if we only are swallowing, returning alternative value, no matching handler was found. + + // no matching handler. + if (returnVal.Equals("nomatch")) + { + throw; + } + else + { + //TODO make spring specific value. + if (!returnVal.Equals("swallow")) + { + return returnVal; + } + else + { + Type returnType = invocation.Method.ReturnType; + return returnType.IsValueType ? Activator.CreateInstance(returnType) : null; + } + } + } + } + + #endregion + + #region IInitializingObject implementation + + /// + /// Invoked by an + /// after it has injected all of an object's dependencies. + /// + /// + ///

+ /// This method allows the object instance to perform the kind of + /// initialization only possible when all of it's dependencies have + /// been injected (set), and to throw an appropriate exception in the + /// event of misconfiguration. + ///

+ ///

+ /// Please do consult the class level documentation for the + /// interface for a + /// description of exactly when this method is invoked. In + /// particular, it is worth noting that the + /// + /// and + /// callbacks will have been invoked prior to this method being + /// called. + ///

+ ///
+ /// + /// In the event of misconfiguration (such as the failure to set a + /// required property) or if initialization fails. + /// + public override void AfterPropertiesSet() + { + if (exceptionHandlers.Count == 0) + { + throw new ArgumentException("At least one handler is required"); + } + IList newExceptionHandlers = new ArrayList(); + foreach (object o in exceptionHandlers) + { + string handlerString = o as string; + if (handlerString != null) + { + IExceptionHandler handler = Parse(handlerString); + if (handler == null) + { + throw new ArgumentException("Was not able to parse exception handler string [" + handlerString + + "]"); + } + newExceptionHandlers.Add(handler); + } + + } + //TODO sync. + exceptionHandlers = newExceptionHandlers; + } + + #endregion + + #region Methods + + /// + /// Invokes handlers registered for the passed exception and + /// + /// The exception to be handled + /// The that raised this exception. + /// The output of + protected virtual object InvokeHandlers(Exception ex, IMethodInvocation invocation) + { + IDictionary callContextDictionary = new Hashtable(); + callContextDictionary.Add("method", invocation.Method); + callContextDictionary.Add("args", invocation.Arguments); + callContextDictionary.Add("target", invocation.Target); + callContextDictionary.Add("e", ex); + object retValue = "nomatch"; + foreach (IExceptionHandler handler in exceptionHandlers) + { + if (handler != null) + { + if (handler.CanHandleException(ex, callContextDictionary)) + { + retValue = handler.HandleException(callContextDictionary); + if (!handler.ContinueProcessing) + { + return retValue; + } + } + } + } + return retValue; + } + + /// + /// Parses the specified handler string, creating an instance of IExceptionHander. + /// + /// The handler string. + /// an instance of an exception handler or null if was not able to correctly parse + /// handler string. + protected virtual IExceptionHandler Parse(string handlerString) + { + ParsedAdviceExpression parsedAdviceExpression = ParseAdviceExpression(handlerString); + + if (!parsedAdviceExpression.Success) + { + log.Warn("Could not parse exception hander statement " + handlerString); + return null; + } + + return CreateExceptionHandler(parsedAdviceExpression); + } + + /// + /// Creates the exception handler. + /// + /// The parsed advice expression. + /// The exception handler instance + protected virtual IExceptionHandler CreateExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) + { + if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0) + { + //TODO support user selection of level, log.Debug , log.Info etc. + LogExceptionHandler handler = new LogExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = "#log.Trace(" + parsedAdviceExpression.ActionExpressionText + ")"; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0) + { + TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0) + { + TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression); + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0) + { + TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression); + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0) + { + SwallowExceptionHandler handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + return handler; + } + else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0) + { + ReturnValueExceptionHandler handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames); + handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression; + handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText; + return handler; + } + else + { + log.Warn("Could not parse exception hander statement " + parsedAdviceExpression.AdviceExpression); + } + return null; + } + + /// + /// Parses the wrapped exception expression. + /// + /// The action. + /// The handler string. + /// + protected string ParseWrappedExceptionExpression(string action, string handlerString) + { + int endOfActionIndex = handlerString.IndexOf(action) + action.Length; + string exceptionAndMessage = handlerString.Substring(endOfActionIndex).Trim(); + int endOfExceptionTypeIndex = exceptionAndMessage.IndexOf(" "); + + string rawExpressionTextPart; + string exception; + //Has two pieces. + if (endOfExceptionTypeIndex > 0) + { + exception = exceptionAndMessage.Substring(0, endOfExceptionTypeIndex).Trim(); + rawExpressionTextPart = exceptionAndMessage.Substring(endOfExceptionTypeIndex).Trim(); + } + else + { + exception = exceptionAndMessage; + if (action.Equals("wrap")) + { + rawExpressionTextPart = "'Wrapped ' + #e.GetType().Name"; + } else + { + rawExpressionTextPart = "'Replaced ' + #e.GetType().Name"; + } + } + + if (action.Equals("wrap")) + { + return string.Format("new {0}({1}, #e)", exception, rawExpressionTextPart); + } else + { + return string.Format("new {0}({1})", exception, rawExpressionTextPart); + } + } + + + + #endregion + } } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs index 8483a52b..66120da3 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs @@ -273,6 +273,21 @@ namespace Spring.Aspects.Exceptions } } + [Test] + public void SwallowReturnTypeIsValueType() + { + string returnHandlerText = "on exception name ArithmeticException swallow"; + ITestObject to = CreateTestObjectProxy(returnHandlerText); + try + { + to.ExceptionalWithReturnValue(new ArithmeticException("Bad Math")); + } + catch (Exception e) + { + Assert.Fail("Should not have thrown exception. Exception type = " + e.GetType()); + } + } + [Test] public void ReturnWithString()