I have some code in here. This is simplified version of a real class:
public class Delayer
{
//it has to be unawaitable
public async void Execute(Action action)
{
await Task.Delay(10).ConfigureAwait(false);
action.BeginInvoke(null, null); //action.Invoke();
}
}
I use it:
private static Task TestFoo()
{
throw new Exception();
}
delayer.Execute(async () =>
{
//do something else
await TestFoo().ConfigureAwait(false);
});
I can't hadle this exception by passing Execute method into try/catch and I can't do it by passing action.BeginInvoke(null, null) into try/catch as well. I can handle it if only I surround async lambda with try/catch when pass it to Execute method.
My question is: why is async lambda executed with await? Because if it weren't executed with await, exception would be swallowed.
I want Execute method to swallow all exceptions thrown from an action. Any ideas how to do it? What do I do wrong?
Addition:
The behavior of Execute must be like "just a fire and forget operation".
Edit
If your really, really want a Fire and Forget method the only thing to do is to
catch all exceptions in the Execute method. But you have to accept an awaitable task if you want to be able to catch exceptions instead of using BeginInvoke on a non-awaitable Action.
public class Delayer
{
public async Task Execute(Func<Task> action) // or public async void Execute(Func<Task> action) if you insist on it.
{
try
{
await Task.Delay(10).ConfigureAwait(false);
await action.Invoke();
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
you can then safely do
void CallDelayedMethod()
{
var delayer = new Delayer();
delayer.Execute(ThrowException);
}
public Task ThrowException()
{
throw new Exception();
}
I would still return a Task and leave it to the caller to ignore it by not awaiting it (fire and forget) or not.
Original answer
You are not following the best practices by using an async void signature in the class Delayer.
public async void Execute(Action action)
should be
public async Task Execute(Action action)
so you can await the call to Execute. Otherwise it is just a fire and forget operation and that makes catching exceptions difficult. By making it awaitbale you can do:
try
{
await Delayer.Execute(...);
}
catch(Exception ex)
{
....
}
From the best practices:
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.
Also, you should have Execute accept a Task if you want to pass awaitable actions to it:
public async Task Execute(Func<Task> action)
{
await Task.Delay(10).ConfigureAwait(false);
await action.Invoke();
}
Related
public static T SyncVer<T>(Func<T> callback)
{
using (new LogContext("new logging context"))
{
try
{
return callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
public static async Task<T> AsyncVer<T>(Func<Task<T>> callback)
{
using (new LogContext("new logging context"))
{
try
{
return await callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
Please consider the code above. You may see most of the code in both functions is the same. I am searching for a way to group them up by overloading them into one so that I don't need to duplicate the content.
Is there a way to take out the similar part of both functions?
Any help provided will be appreciated. Thanks in advance.
Note that Task.FromResult will allocate, and GetAwaiter().GetResult() may dead lock
Personally I would just create two methods and not worry about it.
However, another (and slightly safer) approach is to wrap your callbacks in a ValueTask. ValueTasks work best if they execute synchronously, however they have a few subtle limitations and should never be awaited more than once.
The assumption is, this is all about creation an awaitable and non awaitable delegate overload, code reuse, and awaiting the sync version of this call is not a problem for you.
Given
public static async ValueTask<T> SomethingAsync<T>(Func<T> callback)
=> await SomethingAsync(() => new ValueTask<T>(callback()));
public static async ValueTask<T> SomethingAsync<T>(Func<Task<T>> callback)
=> await SomethingAsync(() => new ValueTask<T>(callback()));
public static async ValueTask<T> SomethingAsync<T>(Func<ValueTask<T>> callback)
{
using (new LogContext("new logging context"))
{
try
{
return await callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
Usage
public static string DoSomething()
{
Console.WriteLine("execute sync");
return "sync result";
}
public static async Task<string> DoSomethingAsync()
{
Console.WriteLine("Execute async");
await Task.Delay(100);
return "async result";
}
...
Console.WriteLine(await SomethingAsync(DoSomething));
Console.WriteLine(await SomethingAsync(DoSomethingAsync));
Output
Create
execute sync
Dispose
sync result
Create
Execute async
Dispose
async result
To add some more efficiencies you can elide wrappers
Exmaple
public static ValueTask<T> SomethingAsync<T>(Func<T> callback)
{
try
{
return SomethingAsync(() => new ValueTask<T>(callback()));
}
catch (Exception e)
{
return ValueTask.FromException<T>(e);
}
}
public static ValueTask<T> SomethingAsync<T>(Func<Task<T>> callback)
{
try
{
return SomethingAsync(() => new ValueTask<T>(callback()));
}
catch (Exception e)
{
return ValueTask.FromException<T>(e);
}
}
Note : ValueTask.FromException is only available for .NET 5.0+
The benefits of this approach :
Less allocations for the sync version of this method.
There is no chance of a deadlock
It doesn't block on async method
It gives you a Value Task overload
The downsides are
You need to wrap the async task in a ValueTask, though it's only a stack allocation
You will need to create two overloads per method (in total three signatures)
Neither version will can be awaited twice.
The sync version is slightly slower as it creates a statemachine
Note : I personally have never had a need to do this, I would just create the two methods ¯\_(ツ)_/¯.
Additional resources
Don't Block on Async Code
Prefer ValueTask to Task, always; and don't await twice
I would try something like this:
public static T SyncVer<T>(Func<T> callback)
{
return AsyncVer(() => Task.FromResult(callback())).GetAwaiter().GetResult();
}
I'm wondering how I can let this code fall in the catch of PassThrough?
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main(string[] args)
{
try
{
await PassThrough(Test());
} catch (Exception) {
Console.WriteLine("caught at invocation");
}
Console.ReadLine();
}
public static async Task PassThrough(Task<bool> test)
{
try
{
var result = await test.ConfigureAwait(false);
// still need to do something with result here...
}
catch
{
Console.WriteLine("never caught... :(");
}
}
/// external code!
public static Task<bool> Test()
{
throw new Exception("something bad");
// do other async stuff here
// ...
return Task.FromResult(true);
}
}
fiddle
The external code should return handle the error path and return Task.FromException? Pass a Func<Task<bool>>?
My recommendation would be to change your PassThrough method to take a Func<Task<bool>> instead of a Task<bool>. This way, you can capture exceptions arising both from the synchronous part of your Test method, as well as the asynchronous task it launches. An added advantage is that asynchronous methods (defined using async and await) can be directly cast to Func<Task> or Func<Task<TResult>>.
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
try
{
await PassThrough(Test);
// Note that we are now passing in a function delegate for Test,
// equivalent to () => Test(), not its result.
}
catch (Exception)
{
Console.WriteLine("caught at invocation");
}
Console.ReadLine();
}
public static async Task PassThrough(Func<Task<bool>> test)
{
try
{
var task = test(); // exception thrown here
var result = await task.ConfigureAwait(false);
// still need to do something with result here...
}
catch
{
Console.WriteLine("caught in PassThrough");
}
}
/// external code!
public static Task<bool> Test()
{
throw new Exception("something bad");
// do other async stuff here
// ...
return Task.FromResult(true);
}
}
Adding to Douglas's answer.
Only catch exceptions if you are able to do something meaningful with them and you can manage them at that level.
Task.FromException basically just places the exception on a task which you would usually return. However, in this case the Async Await Pattern already does this for you. i.e If you just let it fail, the exception will get placed on the task anyway, so there seems no real reason from your code to catch anything.
The only pertinent place you have to think about catching exceptions is in async void as they run unobserved and can cause issues when an exception is thrown
In the following line you are awaiting the PassThrough, not the Test.
await PassThrough(Test());
You could await both if you wanted:
await PassThrough(await Test()); // also need to change the signature of PassThrough from Task<bool> to bool.
...but in both cases the Test will be invoked first. And since it throws an exception, the PassThrough will never be invoked. This is the reason you don't see the "caught in PassThrough" message. The execution never enters this method.
I read that returning void from a C# async call is not good. But I have the following scenario:
public async void MainFunction()
{
await DoSomething()
await DoSomethingMore()
}
public void DoSomething()
{
//some code that I want to execute (fire and forget)
}
public void DoSomethingMore()
{
//some code that I want to execute (fire and forget)
}
Since I just want that function be executed with no return at all. Should i keep it like this, or should I return Task from DoSomething()? If I change it to return Task, since my code doesn't need to return anything at all, what should I return?
If i change it to return Task, since my code need return nothing at
all, what should i return?
Your current code wouldn't compile, as you can't await on a void returning method (because it doesn't return an awaitable, which is a type which exposes a GetAwaiter method).
Any void method in the synchronous world should return a Task in the asynchronous world. This allows for anyone who wishes to asynchronously wait on the async operation, and also gets a chance to handle exceptions properly. using async void means that the exception will either be swallowed, or if set to in the configuration, will be rethrown on an arbitrary threadpool thread. Async should be propagated properly all the way.
Note that when you await both operations in MainFunctionAsync, you're not firing and forgetting, you're asynchronously waiting for each of them to complete, sequentially.
public async Task MainFunctionAsync()
{
await DoSomethingAsync();
await DoSomethingMoreAsync();
}
public Task DoSomethingAsync()
{
// Do meaningful async stuff
}
public Task DoSomethingMoreAsync()
{
// Do more meaningful async stuff
}
you can return either of these
Task.FromCompleted;
Task.FromException(ex);
so your method would be like this:
public void MainFunction()
{
await DoSomething()
await DoSomethingMore()
}
public Task DoSomething()
{
try{
//some code that I want to execute (fire and forget)
return Task.FromCompleted;
}
catch(Exception ex){
return Task.FromException(ex);
}
}
//some code that I want to execute (fire and forget)
}
public Task DoSomethingMore()
{
try{
//some code that I want to execute (fire and forget)
return Task.FromCompleted;
}
catch(Exception ex){
return Task.FromException(ex);
}
}
Supposed you have 2 async method define as bellow:
public async Task<TResult> SomeMethod1()
{
throw new Exception();
}
public async Task<TResult> SomeMethod2()
{
await Task.Delay(50);
throw new Exception();
}
Now if you await on those 2 methods the behavior will be pretty much the same. But if you are getting the task the behavior is different.
If I want to cache the result of such a computation but only when the task run to completion.
I have to take care of the 2 situation:
First Situation:
public Task<TResult> CachingThis1(Func<Task<TResult>> doSomthing1)
{
try
{
var futur = doSomthing1()
futur.ContinueWith(
t =>
{
// ... Add To my cache
},
TaskContinuationOptions.NotOnFaulted);
}
catch ()
{
// ... Remove from the pending cache
throw;
}
}
Second Situation
public Task<TResult> CachingThis2(Func<Task<TResult>> doSomthing)
{
var futur = SomeMethod2();
futur.ContinueWith(
t =>
{
// ... Add To my cache
},
TaskContinuationOptions.NotOnFaulted);
futur.ContinueWith(
t =>
{
// ... Remove from the pending cache
},
TaskContinuationOptions.OnlyOnFaulted);
}
Now I pass to my caching system the method that will execute the computation to cache.
cachingSystem.CachingThis1(SomeMethod1);
cachingSystem.CachingThis2(SomeMethod2);
Clearly I need to duplicate code in the "ConinueWith on faulted" and the catch block.
Do you know if there is a way to make the exception behave the same whether it is before or after an await?
There's no difference in the exception handling required for both SomeMethod1 and SomeMethod2. They run exactly the same way and the exception would be stored in the returned task.
This can easily be seen in this example;
static void Main(string[] args)
{
try
{
var task = SomeMethod1();
}
catch
{
// Unreachable code
}
}
public static async Task SomeMethod1()
{
throw new Exception();
}
No exception would be handled in this case since the returned task is not awaited.
There is however a distinction between a simple Task-returning method and an async method:
public static Task TaskReturning()
{
throw new Exception();
return Task.Delay(1000);
}
public static async Task Async()
{
throw new Exception();
await Task.Delay(1000);
}
You can avoid code duplication by simply having an async wrapper method that both invokes the method and awaits the returned task inside a single try-catch block:
public static async Task HandleAsync()
{
try
{
await TaskReturning();
// Add to cache.
}
catch
{
// handle exception from both the synchronous and asynchronous parts.
}
}
In addition to what I3arnon said in his answer, in case you ContinueWith on async method without the TaskContinuationOptions you specify, exception captured by the Task parameter you receive in the continuation handler can be handled in the following way:
SomeMethod1().ContinueWith(ProcessResult);
SomeMethod2().ContinueWith(ProcessResult);
With ProcessResult handler which looks like:
private void ProcessResult<TResult>(Task<TResult> task)
{
if (task.IsFaulted)
{
//remove from cahe
}
else if (task.IsCompleted)
{
//add to cache
}
}
I am trying to write a method that tries to execute an action but swallows any exceptions that are raised.
My first attempt is the following:
public static void SafeExecute(Action actionThatMayThrowException) {
try {
actionThatMayThrowException();
} catch {
// noop
}
}
Which works when called with a synchronous action:
SafeExecute(() => {
throw new Exception();
});
However fails when called with an asynchronous action:
SafeExecute(async () => {
await Task.FromResult(0);
throw new Exception();
});
Is is possible to write a method that handles both scenarios?
To correctly handle async delegates you shouldn't use Action (this will cause the lambda expression to be async void which is dangerous and should be avoided), you should use Func<Task> to be able to await it:
public static async Task SafeExecute(Func<Task> asyncActionThatMayThrowException)
{
try
{
await asyncActionThatMayThrowException();
}
catch
{
// noop
}
}
This will solve the async case, but not the synchronous case. You can't do both with a single method. To do that you would need a different method, but it can still call the async one to enable reuse:
private static readonly Task<object> _completedTask = Task.FromResult<object>(null);
public static void SafeExecute(Action actionThatMayThrowException)
{
SafeExecute(() =>
{
actionThatMayThrowException();
return _completedTask;
});
}
I wouldn't actually recommend disregarding unhandled exceptions in this way. You should consider at least logging the exception.