How to prevent an action parameter from being an async lambda? - c#

I am writing a small wrapper (MyWrapper) for use in unit tests. Its purpose is to wrap test code with a try-catch in order to catch one specific exception (MySpecialException) and then ignore the test.
Why I do that should not be relevant for this question.
Given the code below, how do I prevent others from passing an Action and using async like this?
Or in other words: How do I force them to use MyWrapper.ExecuteAsync(Func<Task>) instead?
using System;
using System.Threading.Tasks;
using NUnit.Framework;
namespace PreventAsyncActionLambdaExample
{
[TestFixture]
public class Example
{
[Test]
public async Task ExampleTest()
{
// How do I prevent others from passing an action and using async like this?
// Or in other words: How do I force them to use MyWrapper.ExecuteAsync(Func<Task>) instead?
MyWrapper.Execute(async () =>
{
var cut = new ClassUnderTest();
await cut.DoSomethingAsync();
Assert.Fail("Problem: This line will never be reached");
});
}
}
public static class MyWrapper
{
// This method SHOULD NOT, BUT WILL be used in this example
public static void Execute(Action action)
{
try
{
action();
}
catch (MySpecialException)
{
Assert.Ignore("Ignored due to MySpecialException");
}
}
// This method SHOULD BE USED in this example, BUT WILL NOT be used.
public static async Task ExecuteAsync(Func<Task> func)
{
try
{
await func();
}
catch (MySpecialException)
{
Assert.Ignore("Ignored due to MySpecialException");
}
}
}
public class MySpecialException : Exception
{
// This is another exception in reality which is not relevant for this example
}
public class ClassUnderTest
{
public Task DoSomethingAsync()
{
return Task.Delay(20); // Simulate some work
}
}
}

I am afraid that you can't really prevent this at compile-time but you could write another overload that will be picked-up in this case to tell them that they are supposed to use ExecuteAsync instead:
public static Task Execute(Func<Task> action)
{
throw new Exception("Please use the ExecuteAsync(Func<Task> func) method instead if you will be passing async lambdas");
}

As mentioned in other answers, I do not think you can prevent it in compile time. However, you can do a hacky workaround and throw an exception. Inspired by this answer. It might not be a good solution, but it could at least make the test fail.
public static bool IsThisAsync(Action action)
{
return action.Method.IsDefined(typeof(AsyncStateMachineAttribute),
false);
}
// This method SHOULD NOT, BUT WILL be used in this example
public static void Execute(Action action)
{
try
{
if (IsThisAsync(action))
{
Console.WriteLine("Is async");
throw new ArgumentException("Action cannot be async.", nameof(action));
}
else
{
Console.WriteLine("Is not async");
}
action();
}
catch (MySpecialException)
{
}
}
And tests:
[TestClass]
public class MyWrapperTests
{
// Will not pass
[TestMethod]
public void ShouldAllowAsyncAction()
{
// This will throw an exception
MyWrapper.Execute(async () =>
{
Assert.IsTrue(true);
await Task.Run(() =>
{
Console.WriteLine("Kind of async");
});
});
}
// Will pass, since ArgumentException is expected.
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void ShouldThrowArgumentExceptionWhenAsync()
{
// This will throw an exception. But that's expected.
MyWrapper.Execute(async () =>
{
Assert.IsTrue(true);
await Task.Run(() =>
{
Console.WriteLine("Kind of async");
});
});
}
// Passes
[TestMethod]
public void ShouldAllowSyncAction()
{
MyWrapper.Execute(() =>
{
Assert.IsTrue(true);
});
}
}

Related

'Catch exception' extension on Task class

I have code like this:
try { await myFunc(); }
catch (MyException ex)
{
switch (ex.Code)
{
case 1: ... break;
case 2: ... break;
...
}
}
And was wondering is it possible to make all that look something like this:
...
{
await myFunc().HandleMyExeptions(OnMyException);
}
private void OnMyException(int exCode)
{
switch (ex.Code)
{
case 1: ... break;
case 2: ... break;
...
}
}
where I would create extension class for tasks something like this
public static class TaskExtensions
{
public static void HandleErrors(this Task task, Action<int> handleError)
{
// I don't know what would go here nor whether the header of
// this function is a step in a good direction
}
}
It's going to look something like this:
public static Task HandleErrors(this Task task, Action<int> handleError) =>
task.ContinueWith(t =>
{
if (t.Status == TaskStatus.Faulted && t.Exception.InnerException is MyException ex)
{
handleError(ex.Code);
}
});
Had you provided sample code in your question that showed how your existing exception handling worked, then I would have fully tested this, but you didn't. If you care to write that code and add it to your question, then I'll do the testing.
A simpler approach using await:
public static async Task HandleErrors(this Task task, Action<int> handleError)
{
try
{
await task;
}
catch (MyException ex)
{
handleError(ex.Code);
}
}

How to use action delegate to avoid if else

I have the following code:
public class NotificationService {
private readonly Dictionary<NotificationMessageType, Action<IList<RecipientDetail>, NotificationMessageType>> _actionMap;
public NotificationService() [
_actionMap = new Dictionary<NotificationMessageType, Action<IList<RecipientDetail>, NotificationMessageType>> ();
_actionMap.Add(NotificationMessageType.SessionBookedReminder, new Action<IList<RecipientDetail>, NotificationMessageType>(GenerateNotificationsAsync)); //getting errror here because of async await
}
public async Task GenerateNotificationsAsync(IList<RecipientDetail> usersToNotify, NotificationMessageType messageType)
{
Would like to avoid if else here:
if(messageType == NotificationMessageType.SessionBookedReminder)
{
await Task.WhenAll(usersToNotify.Select(u => GenerateBookingNotificationAsync(u, messageType)).ToArray());
}
else
{
await Task.WhenAll(usersToNotify.Select(u => SendNotificationAsync(u, messageType)).ToArray());
}
}
public async Task GenerateNotificationsAsync(IList<RecipientDetail> usersToNotify, NotificationMessageType messageType)
{
}
public async Task GenerateBookingNotificationAsync(RecipientDetail userToNotify, NotificationMessageType messageType)
{
}
}
How can I use action delegate to avoid if else. I've tried with following, but getting error due to async await.
Can anyone help how to do the right way?
Thanks
Your dictionary must match the method declaration, your methods returns a task, so your
Action<IList<RecipientDetail>, NotificationMessageType>
Must be changed to something like
Func<IList<RecipientDetail>, NotificationMessageType,Task>
your method must return a task in order to use it in a async/await manner

Avoid Try Catch Stements with custom ErrorHandler class - C#

I have a class which exposes some functionality,
and I want to ensure exceptions will be handled by a custom ErrorHandler class.
Currently I can achieve this by a try / catch statement per each method, and process the exception by the error handler there.
My question is if there is a better way / design pattern to do it.
Code:
public class BasicErrorHandler
{
public void ProcessException(Exception ex)
{
//Does error handling stuff
}
}
public class Manager
{
BasicErrorHandler _errorHandler;
public Manager()
{
_errorHandler = new BasicErrorHandler();
}
public void MethodA()
{
try
{
//Does Something
}
catch(Exception ex)
{
_errorHandler.ProcessException(ex);
}
}
public void MethodB()
{
try
{
//Does Something Else
}
catch(Exception ex)
{
_errorHandler.ProcessException(ex);
}
}
}
In keeping with DRY principles, you could just wrap your try...catch logic into into own method which takes a predicate of the actual work to do:
public class Manager
{
BasicErrorHandler _errorHandler;
public Manager()
{
_errorHandler = new BasicErrorHandler();
}
public void MethodA()
{
DoWork( () => {
// do something interesting here
});
}
public void MethodB()
{
DoWork( () => {
// do something else interesting here
});
}
private void DoWork(Action action)
{
try
{
action();
}
catch(Exception ex)
{
_errorHandler.ProcessException(ex);
}
}
}
I've crafted this quickly and without thinking too much in the implications, but if you want to avoid all the try/catch blocks, you could do something like:
public class BasicErrorHandler
{
public void ProcessException(Exception ex)
{
//Does error handling stuff
}
public void Do(Action act)
{
try
{
act();
}
catch(Exception ex)
{
ProcessException(ex);
}
}
}
And then use it like:
public class Manager
{
BasicErrorHandler _errorHandler;
public Manager()
{
_errorHandler = new BasicErrorHandler();
}
public void MethodA()
{
_errorHandler.Do(() => {
//Does Something
});
}
public void MethodB()
{
_errorHandler.Do(() => {
//Does Something Else
});
}
}
Design patterns are there to solve a problem. Which problem are you trying to solve? What is wrong with the Try Catch blocks?
Only thing I can imagine is you want to have more clean code. Some answers suggest a helper method with an action. Given the helper methods that encapsulate a delegate: Do consider the impact on your stack trace and debugging sessions using these delegates. It might make logging etc more hard to understand.
If your intend is to do separation of concern, I would say If you can't handle it, just don't catch the exception. Let the class invoking the method handle it. If you insist to have a handler in your class, I would suggest Inversion of Control. That way, your class is not in control of determining which class should handle its exceptions.
Rx .net is for You. Advanced error handling gives You the ability to highly customize Your error handling. Check out the pages about that.
For example:
var source = new Subject<int>();
var result = source.Catch<int, TimeoutException>(tx=>Observable.Return(-1));
result.Dump("Catch");
source.OnNext(1);
source.OnNext(2);
source.OnError(new ArgumentException("Fail!"));
You'll get the following output:
Catch-->1
Catch-->2
Catch failed-->Fail!
The number of retries, the handling of how much time a method can take, everything can be configured.
The following is an Aspect oriented method of soling the problem, this makes use of PostSharp to do the weaving.
[Serializable]
public class HandleExceptionsAttribute : OnExceptionAspect {
/// <summary>
/// Initializes a new instance of the <see cref="HandleExceptionsAttribute"/> class.
/// </summary>
public HandleExceptionsAttribute() {
AspectPriority = 1;
}
public override void OnException(MethodExecutionArgs args) {
//Suppress the current transaction to ensure exception is not rolled back
using (var s = new TransactionScope(TransactionScopeOption.Suppress)) {
//Log exception
using (var exceptionLogContext = new ExceptionLogContext()) {
exceptionLogContext.Set<ExceptionLogEntry>().Add(new ExceptionLogEntry(args.Exception));
exceptionLogContext.SaveChanges();
}
}
}
}
[HandleExceptions]
public class YourClass {
}

Unit testing exception property

I have exception
class SyntaxError : Exception {
public SyntaxError(int l) {
line = l;
}
public int line;
}
I'm using unit tests to test class Parser which on specific input should throw exception above. I'm using code like this:
[TestMethod]
[ExpectedException(typeof(Parser.SyntaxError))]
public void eolSyntaxError()
{
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
parser.eol();
}
Is there any smart simple way to check if SyntaxError.line == 1?
Best I come up with is:
[TestMethod]
public void eolSyntaxError()
{
try {
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
parser.eol();
Assert.Fail();
} catch (SyntaxError e) {
Assert.AreEqual(1, e.line);
}
}
I don't like it very much, is there better way?
Consider using FluentAssertions. Your test will then look like this:
[TestMethod]
public void eolSyntaxError()
{
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
Action parseEol = () => parser.eol();
parseEol
.ShouldThrow<SyntaxError>()
.And.line.Should().Be(1);
}
Otherwise, your approach is pretty much as good as it gets.
You could write a method similar to the one in NUnit
public T Throws<T>(Action code) where T : Exception
{
Exception coughtException = null;
try
{
code();
}
catch (Exception ex)
{
coughtException = ex;
}
Assert.IsNotNull(coughtException, "Test code didn't throw exception");
Assert.AreEqual(coughtException.GetType(), typeof(T), "Test code didn't throw same type exception");
return (T)coughtException;
}
And then you can use it in your test method
Parser.SyntaxError exception = Throws<Parser.SyntaxError>(() => parser.eol());
Assert.AreEqual(1, exception.line);
As per my comment, if the line at which you encounter the syntax error is relevant, then include it in your custom exception class, like so.
public class SyntaxError : Exception
{
public SyntaxError(int atLine)
{
AtLine = atLine;
}
public int AtLine { get; private set; }
}
Then it's easy to test.
EDIT - After having read the question (!) here's a simple additional Assert method which will tidy up your exception assertions.
public static class xAssert
{
public static TException Throws<TException>(Action a) where TException : Exception
{
try
{
a();
}
catch (Exception ex)
{
var throws = ex as TException;
if (throws != null)
return throws;
}
Assert.Fail();
return default(TException);
}
}
Usage as follows...
public class Subject
{
public void ThrowMyException(int someState)
{
throw new MyException(someState);
}
public void ThrowSomeOtherException()
{
throw new InvalidOperationException();
}
}
public class MyException : Exception
{
public int SomeState { get; private set; }
public MyException(int someState)
{
SomeState = someState;
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var subject = new Subject();
var exceptionThrown = xAssert.Throws<MyException>(() => { subject.ThrowMyException(123); });
Assert.AreEqual(123, exceptionThrown.SomeState);
}
}
I am not aware of an out of the box solution for this, but I have seen the concept of expectations which work like this:
[TestMethod]
public void EolSyntaxError()
{
Expectations.Expect<(SyntaxError>(
() =>
{
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
parser.eol();
},
e =>
{
Assert.AreEqual(1, e.line);
});
}
Expectations needs to be implemented. I reckon there will be libraries out there which already do this. Anyhow, the Expect method in Expectations could look like this:
public static void Expect<TExpectedException>(
System.Action action,
System.Action<TExpectedException> assertion) where TExpectedException : Exception
{
if (action == null) { throw new ArgumentNullException("action"); }
try
{
action.Invoke();
Assert.Fail(string.Format("{0} expected to be thrown", typeof(TExpectedException).Name));
}
catch (TExpectedException e)
{
assertion.Invoke(e);
}
}

Fody Async MethodDecorator to Handle Exceptions

I am trying to use Fody to wrap all exceptions thrown from a method with a common exception format.
So I have added the required interface declaration and class implementation that looks like this :
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
[module: MethodDecorator]
public interface IMethodDecorator
{
void Init(object instance, MethodBase method, object[] args);
void OnEntry();
void OnExit();
void OnException(Exception exception);
void OnTaskContinuation(Task t);
}
[AttributeUsage(
AttributeTargets.Module |
AttributeTargets.Method |
AttributeTargets.Assembly |
AttributeTargets.Constructor, AllowMultiple = true)]
public class MethodDecorator : Attribute, IMethodDecorator
{
public virtual void Init(object instance, MethodBase method, object[] args) { }
public void OnEntry()
{
Debug.WriteLine("base on entry");
}
public virtual void OnException(Exception exception)
{
Debug.WriteLine("base on exception");
}
public void OnExit()
{
Debug.WriteLine("base on exit");
}
public void OnTaskContinuation(Task t)
{
Debug.WriteLine("base on continue");
}
}
And the domain implementation that looks like this
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
namespace CC.Spikes.AOP.Fody
{
public class FodyError : MethodDecorator
{
public string TranslationKey { get; set; }
public Type ExceptionType { get; set; }
public override void Init(object instance, MethodBase method, object[] args)
{
SetProperties(method);
}
private void SetProperties(MethodBase method)
{
var attribute = method.CustomAttributes.First(n => n.AttributeType.Name == nameof(FodyError));
var translation = attribute
.NamedArguments
.First(n => n.MemberName == nameof(TranslationKey))
.TypedValue
.Value
as string;
var exceptionType = attribute
.NamedArguments
.First(n => n.MemberName == nameof(ExceptionType))
.TypedValue
.Value
as Type;
TranslationKey = translation;
ExceptionType = exceptionType;
}
public override void OnException(Exception exception)
{
Debug.WriteLine("entering fody error exception");
if (exception.GetType() != ExceptionType)
{
Debug.WriteLine("rethrowing fody error exception");
//rethrow without losing stacktrace
ExceptionDispatchInfo.Capture(exception).Throw();
}
Debug.WriteLine("creating new fody error exception");
throw new FodyDangerException(TranslationKey, exception);
}
}
public class FodyDangerException : Exception
{
public string CallState { get; set; }
public FodyDangerException(string message, Exception error) : base(message, error)
{
}
}
}
This works fine for synchronous code. But for asynchronous code the exception handler is skipped, even though all the other IMethodDecorator are executed (like OnExit, and OnTaskContinuation).
For example, looking at the following test class :
public class FodyTestStub
{
[FodyError(ExceptionType = typeof(NullReferenceException), TranslationKey = "EN_WHATEVER")]
public async Task ShouldGetErrorAsync()
{
await Task.Delay(200);
throw new NullReferenceException();
}
public async Task ShouldGetErrorAsync2()
{
await Task.Delay(200);
throw new NullReferenceException();
}
}
I see that ShouldGetErrorAsync produces the following IL code :
// CC.Spikes.AOP.Fody.FodyTestStub
[FodyError(ExceptionType = typeof(NullReferenceException), TranslationKey = "EN_WHATEVER"), DebuggerStepThrough, AsyncStateMachine(typeof(FodyTestStub.<ShouldGetErrorAsync>d__3))]
public Task ShouldGetErrorAsync()
{
MethodBase methodFromHandle = MethodBase.GetMethodFromHandle(methodof(FodyTestStub.ShouldGetErrorAsync()).MethodHandle, typeof(FodyTestStub).TypeHandle);
FodyError fodyError = (FodyError)Activator.CreateInstance(typeof(FodyError));
object[] args = new object[0];
fodyError.Init(this, methodFromHandle, args);
fodyError.OnEntry();
Task task;
try
{
FodyTestStub.<ShouldGetErrorAsync>d__3 <ShouldGetErrorAsync>d__ = new FodyTestStub.<ShouldGetErrorAsync>d__3();
<ShouldGetErrorAsync>d__.<>4__this = this;
<ShouldGetErrorAsync>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<ShouldGetErrorAsync>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <ShouldGetErrorAsync>d__.<>t__builder;
<>t__builder.Start<FodyTestStub.<ShouldGetErrorAsync>d__3>(ref <ShouldGetErrorAsync>d__);
task = <ShouldGetErrorAsync>d__.<>t__builder.Task;
fodyError.OnExit();
}
catch (Exception exception)
{
fodyError.OnException(exception);
throw;
}
return task;
}
And ShouldGetErrorAsync2 generates :
// CC.Spikes.AOP.Fody.FodyTestStub
[DebuggerStepThrough, AsyncStateMachine(typeof(FodyTestStub.<ShouldGetErrorAsync2>d__4))]
public Task ShouldGetErrorAsync2()
{
FodyTestStub.<ShouldGetErrorAsync2>d__4 <ShouldGetErrorAsync2>d__ = new FodyTestStub.<ShouldGetErrorAsync2>d__4();
<ShouldGetErrorAsync2>d__.<>4__this = this;
<ShouldGetErrorAsync2>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<ShouldGetErrorAsync2>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <ShouldGetErrorAsync2>d__.<>t__builder;
<>t__builder.Start<FodyTestStub.<ShouldGetErrorAsync2>d__4>(ref <ShouldGetErrorAsync2>d__);
return <ShouldGetErrorAsync2>d__.<>t__builder.Task;
}
If I call ShouldGetErrorAsync, Fody is intercepting the call, and wrapping the method body in a try catch. But if the method is async, it never hits the catch statement even though the fodyError.OnTaskContinuation(task) and fodyError.OnExit() are still called.
On the other hand, ShouldGetErrorAsync will handle the error just fine, even though there is no error handling block in the IL.
My question is, how should Fody be generating the IL to properly inject the error block and make it so async errors are intercepted?
Here is a repo with tests that reproduces the issue
You are only placing the try-catch around the content of the 'kick-off' method, this will only protect you up to the point where it first needs to reschedule (the 'kick-off' method will end when the async method first needs to reschedule and so will not be on the stack when the async method resumes).
You should look at modifying the method implementing IAsyncStateMachine.MoveNext() on the state machine instead. In particular, look for the call to SetException(Exception) on the async method builder (AsyncVoidMethodBuilder, AsyncTaskMethodBuilder or AsyncTaskMethodBuilder<TResult>) and wrap the exception just before passing it in.
await sure makes asynchronous methods look simple, doesn't it? :) You just found a leak in that abstraction - the method usually returns as soon as the first await is found, and your exception helper has no way to intercept any later exceptions.
What you need to do is implement both the OnException, and handle the return value from the method. When the method returns, and the task isn't completed, you need to wind up an error continuation on the task, which needs to handle exceptions the way you want them to be handled. The Fody guys thought of that - that's what the OnTaskContinuation is for. You need to check the Task.Exception to see if there's an exception lurking in the task, and handle it however you need to.
I think this will only work if you want to rethrow the exception while doing logging or something - it does not allow you to replace the exception with something different. You should test that :)

Categories

Resources