HttpContext is null in error handler when exception is thrown from an async service

It can be replicated with this example.

[Route("/hello")]
public class Hello
{
}

public class HelloService : Service 
{
    public async Task<object> Any(Hello request) 
    {
        await Task.Delay(10);
        throw new NotImplementedException("async");
    }
}

// In the AppHost I have this exception handler
ServiceExceptionHandlers.Add((req, request, exception) =>
{
    Debug.WriteLine($"ServiceExceptionHandlers - HttpContext is null: {System.Web.HttpContext.Current == null}");
    return DtoUtils.CreateErrorResponse(req, exception);
});

I’m expecting the HttpContext to be available in the error handler like it would be if it had been synchronous service, but it’s not. ResponseFilters are affected as well for async services.

I had a peek in the ServiceStack code and it looks to me like the problem is in the ServiceRunner.cs class when the response task is awaited: https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/Host/ServiceRunner.cs#L127

The task is awaited with .ContinueWith() wich doesn’t capture the syncronization context by default, so when the continuation is executed the SynchronizationContext.Current is null when it should be AspNetSynchronizationContext.

If TaskScheduler.FromCurrentSynchronizationContext() is passed to ContinueWith it works as expected.

The Async callbacks can be overridden with:

class MyAsyncContext : AsyncContext 
{
    public override Task<object> ContinueWith(IRequest req, Task task, Func<Task, object> fn)
    {
        return task.ContinueWith(fn, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

Then assigning ServiceStack to use your custom impl with:

HostContext.Async = new MyAsyncContext();

Can you let me know if that resolves the issue? as I’ll look into adding it by default.

Yep that solves the issue, thank you :wink:

I found one more spot where the continuations aren’t executed in the corret context. When validation rules are executed asynchronously and they fail, the continuation doesn’t capture the context and when the ServiceExceptionHandler is called the HttpContext is null as well.

It doesn’t use the AsyncContext you mentioned above, so it’s not possible to override the ContinueWith behavior.

I’ve also made the async Validation filter overridable with HostContext.Async in this commit.

This change is available from v4.5.9 that’s now available on MyGet.