9

Could someone point me to a resource that would help explain how web api (specifically using Owin Self Host) handles request cancellation?

Here's the sequence of events i'm observing:

  • someone makes a GET from chrome
  • Api controller (through some layers) fires off an async SQL query
  • someone hits the X button in chrome (i don't know exactly what happens on socket for this)

What happens next in Web Api??

There was some code running in a controller, does the thread running it get aborted? If it was an async controller awaiting another Task, does that task still have an awaiter in case it returns with an exception?

For context: I do have an async controller awaiting a Task (this is the only call site) which looks to be throwing an unobserved exception in some edge cases. I haven't been able to isolate or re-produce yet :)

I did find something called HttpResponse.ClientDisconnectedToken, but don't know well that is supported in Owin Selfhost + is it even the good thing to use for all user cancels.

VMAtm
  • 27,943
  • 17
  • 79
  • 125
Vivek
  • 2,103
  • 17
  • 26
  • We can't help you unless you lost your code. This seems like someone is firing off a task which goes unobserved, as the exception says. I'm assuming this is .NET 4.0 – Yuval Itzchakov May 07 '15 at 20:18
  • @YuvalItzchakov: Sorry if the exception part is confusing (edited to remove it). I had just put it as context for why i want to understand what web api is doing with the request, my real question is still around what does web api do? – Vivek May 07 '15 at 20:52
  • is this just another way of asking the same question you asked earlier: http://stackoverflow.com/questions/30109260/owen-selfhost-webapi-client-closing-the-connection-during-response-raises-an-e ? – Claies May 07 '15 at 21:15
  • @Claies - Hmm i see how they've ended up similar, but they are very much separate. I think i made the statement of this question very generic, the specific thing i want to find out here is how an aborted request affects a task that is being awaited. This one is major, the other is a nice to have fix. – Vivek May 07 '15 at 21:29

2 Answers2

3

I've dealt with this by handing the System.OperationCanceledException in a custom middleware I've registered before WebApi.

public class ExceptionHanldingMiddleware : OwinMiddleware
{
    public override async Task Invoke(IOwinContext context)
    {
        try
        {
            await Next.Invoke(context);
        }
        catch (OperationCanceledException) when (context.Request.CallCancelled.IsCancellationRequested)
        {
            //swallow user-agent cancelling request.
            _log.Trace($"client disconnected on request for: {context.Request.Path}.");
        }
        catch (Exception ex)
        {
            _log.Error(ex);
            context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
            context.Response.ReasonPhrase = "Internal Server Error";
        }
    }   
}
Dav Evans
  • 4,031
  • 7
  • 41
  • 60
0

As you stated that your async controller is awaiting for a Task, which sometimes got some exception, I suggest you ContinueWith extension method for a task, which can be run only then your task is faulted, like this:

task.ContinueWith(
       t =>
       logger.Error(t.Exception.Message, t.Exception);
       , TaskContinuationOptions.OnlyOnFaulted);

This is a default mechanism to handle the exceptions, and this will work in OWIN application.

Second, as for the cancellation: task can be started with a CancellationToken structure, which can be used for a cancelling the task during the execution. You can read more in the MSDN article.

HttpResponse.ClientDisconnectedToken is used for a situation when the client has been disconnected and the request should not be proceed in execution.

You can use this token, or create your own with CancellationTokenSource, like this:

var source = new CancellationTokenSource();
var token = source.Token;

var task = Task.Factory.StartNew(() =>
{

    // Were we already canceled?
    ct.ThrowIfCancellationRequested();

    var moreToDo = true;
    while (moreToDo)
    {
        // Poll on this property if you have to do 
        // other cleanup before throwing. 
        if (ct.IsCancellationRequested)
        {
            // Clean up here, then...
            ct.ThrowIfCancellationRequested();
        }

    }
}, token);
VMAtm
  • 27,943
  • 17
  • 79
  • 125
  • Thanks for showing usage on that token, but that's way down the line. I haven't even confirmed what's going on yet :( – Vivek May 08 '15 at 15:21
  • Try to add the exception handling – VMAtm May 08 '15 at 17:53
  • > HttpResponse.ClientDisconnectedToken is used for a situation when the client has been disconnected and the request should not be proceed in execution. You can use this token... But how to reach this token? `HttpContext.Current == null` for OWIN self-hosted app... – greatvovan Jul 05 '17 at 19:17
  • You need the `Response`, not the context – VMAtm Jul 05 '17 at 20:32