Josh M. Josh M. - 2 months ago 25
ASP.NET (C#) Question

Async lambda: "a task was cancelled"

Here's the workflow:


  1. Incoming HTTP request to WebApi2 endpoint.

  2. Make synchronous (e.g. not async) call to get some data.

  3. Map response from DB entity to API model.
    a. Executes AutoMapper mapping.
    b. Includes the following snippet (see below).
    c. If operation is "quick", no issue. If operation is "slow", then "a task was cancelled" exception is thrown.



I get lucky in cases when the mapping action is quick. But if I add a
Task.Delay(2000)
, then I get the exception in question. It seems that ASP.NET is not "waiting" for my async lamba to complete?

Here is the body of the mapping expression:

mapping.AfterMap(async (entity, model) => {
var child = await _childRepo.Get(entity.ChildId);
await Task.Delay(2000); // For testing, of course.
if (child != null)
{
// Fill in some properties on model
}
});


Note that this is example code, and I don't intend to make additional DB/repo calls during mapping in "real life".

Answer

AfterMap takes an Action, which is a synchronous delegate, not an asynchronous delegate (as I explain on my blog). As such, it does not work as expected with async lambdas.

In this case (since the delegate returns void), the compiler will actually allow an async lambda; however, it will compile to an async void method. (The compiler does this to allow async event handlers). As I describe in my MSDN article on async best practices, you should avoid async void.

One of the reasons to avoid async void is that it is very difficult to detect when an async void method has completed. In fact, (with the exception of WebForm lifetime events), ASP.NET will not even attempt to do so.

Comments