Should we use CancellationToken with MVC/Web API controllers?

26,839

Solution 1

You should use it. Right now it only applies if you have an AsyncTimeout, but it's likely that a future MVC/WebAPI version will interpret the token as "either timeout or the client disconnected".

Solution 2

You could use this

public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
    CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
    using (var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken))
    {
        IEnumerable<ReportItem> items;
        using (ApplicationDbContext context = new ApplicationDbContext())
        {
            items = await context.ReportItems.ToArrayAsync(source.Token);
        }
        return View(items);
    }
}

taken from here.

Solution 3

Users can cancel requests to your web app at any point, by hitting the stop or reload button on your browser. Typically, your app will continue to generate a response anyway, even though Kestrel won't send it to the user. If you have a long running action method, then you may want to detect when a request is cancelled, and stop execution.

You can do this by injecting a CancellationToken into your action method, which will be automatically bound to the HttpContext.RequestAborted token for the request. You can check this token for cancellation as usual, and pass it to any asynchronous methods that support it. If the request is cancelled, an OperationCanceledException or TaskCanceledException will be thrown.

Below link explains this scenario in detail.

https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/

Share:
26,839
user1224129
Author by

user1224129

Updated on August 04, 2020

Comments

  • user1224129
    user1224129 almost 4 years

    There are different examples for async controllers. Some of them use CancellationToken in method definition:

    public async Task<ActionResult> ShowItem(int id, CancellationToken cancellationToken)
    {
        await Database.GetItem(id, cancellationToken);
        ...
    

    But other examples and even the default ASP.NET projects for VS2013 don't use CancellationToken at all and work without it:

    public async Task<ActionResult> ShowItem(int id)
    {
        await Database.GetItem(id);
        ...
    

    It's not clear, if we should use CancellationToken in controllers or not (and why).

  • Drew Noakes
    Drew Noakes about 9 years
    Has the situation with Web API changed with respect to cancellation tokens and disconnected clients?
  • Stephen Cleary
    Stephen Cleary about 9 years
    @DrewNoakes: AFAIK it has not yet. I believe this will be fixed in ASP.NET vNext.
  • Jonathan Allen
    Jonathan Allen almost 9 years
    I just tested it under VS 2015 and hitting stop in the browser did trigger the cancellation token.
  • eesh
    eesh over 8 years
    How would you pass a Cancellation Token from a C# Web Client to a Get API method? How do you serialize the cancellation token into the URL string?
  • Stephen Cleary
    Stephen Cleary over 8 years
    @eesh: I wouldn't try that at all. Instead, consider having the client close its connection when a cancellation token is triggered; and having the server take a cancellation token as an argument (which is automatically supplied by WebAPI and canceled when the connection is dropped).
  • Miles
    Miles over 6 years
    You MUST dispose LinkedTokenSource because it will never be collected by GC and it will cause memory leak. MSDN: Notice that you must call Dispose on the linked token source when you are done with it. msdn.microsoft.com/en-us/library/dd997364.aspx
  • Leonid Vasilev
    Leonid Vasilev over 6 years
    In this case cancellation token behavior depends on framework version and server implementation. See CancellationToken issue in ASP.NET MVC GitHub repository.
  • Tomas Kubes
    Tomas Kubes almost 5 years
    I tested it (F5, Esc) on React App and it works with Firefox and it does not work with Chrome and Edge.
  • SeanStanden
    SeanStanden over 4 years
    According to the reference, this process is required to make the cancellation token work with MVC 5; "...for some reason, MVC 5 only supports cancellation if you use the AsyncTimeout attribute.". The article points out that "Everything works as expected in both ASP.NET Core MVC and in Web API...". i.e. If you're using .NET Core then you need only pass the CancellationToken through as normal.
  • Triynko
    Triynko almost 4 years
    So Chrome and Edge are incorrectly keeping the connection to the server open AFTER the tab/window is closed?
  • Stephen Cleary
    Stephen Cleary almost 4 years
    @Triynko: I'm not sure why that would be incorrect behavior, assuming HTTP 1.1 or newer.
  • jenson-button-event
    jenson-button-event over 3 years
    and ajax requests in SPAs?