Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between HttpContext.RequestAborted and CancellationToken parameter?

I'm trying to create an async view component for ASP.NET Core 2.0. It will do an action that should be cancelled when the user navigates away from the page. I've got the following options:

  1. Using the HttpContext.RequestAborted
  2. Using a CancellationToken parameter
  3. I could also chain the tokens

Option 1 looks like this:

public class AmazingMessageViewComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(string text, int wait)
    {
        //uses request aborted
        await Task.Delay(wait, HttpContext.RequestAborted);
        return View<string>(text);
    }
}

Option 2 looks like this:

public class AmazingMessageViewComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(CancellationToken cancellationToken, string text, int wait)
    {
        await Task.Delay(wait, cancellationToken);
        return View<string>(text);
    }
}

Both action do not work with Kestrel (looks like a bug). In both cases the tokens are filled (maybe because of struct?)

What is the difference and what should I use?

like image 915
Kees C. Bakker Avatar asked Nov 07 '17 08:11

Kees C. Bakker


People also ask

When should I use CancellationToken?

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.

What is a CancellationToken?

A CancellationToken enables cooperative cancellation between threads, thread pool work items, or Task objects. You create a cancellation token by instantiating a CancellationTokenSource object, which manages cancellation tokens retrieved from its CancellationTokenSource.

What is CancellationToken in .NET core?

So CancellationToken can be used to terminate a request execution at the server immediately once the request is aborted or orphan. Here we are going to see some sample code snippets about implementing a CancellationToken for Entity FrameworkCore, Dapper ORM, and HttpClient calls in Asp.

What is cancellation token in Web API C#?

Cancellation is a way to signal to an async task that it should stop doing whatever it happens to be doing. In . NET, this is done using a CancellationToken. An instance of a cancellation token is passed to the async task and the async task monitors the token to see if a cancellation has been requested.


1 Answers

I know this is a 2 months old issue, but I have been struggling with this today too and came to some conclusions.


What is the difference and what should I use?

According to this thread these are exactly the same things. From CancellationTokenModelBinder source:

var model = (object)bindingContext.HttpContext.RequestAborted;

I can confirm, I always get the same values from HttpContext.RequestAborted and CancellationToken injection.

Advantage of HttpContext.RequestAborted is that it is available in all controller's methods, not just actions. The CancellationToken parameter is IMHO better readable but if you have a number of nested methods that need to react to the token, it may become impractical to propagate it through their parameters. I would just use the one that better suits your needs.


From the same thread, another post:

This only works in 2.0 not in 1.x

I know, this is not your case but it was mine.


Finally, still from the same thread and especially discussion here, there's a problem in IIS (specifically in its interface with Kestrel). AFAIK you have to use Kestrel and optionally (mandatory for 1.x) a reverse proxy such as IIS, Apache or Nginx. I believe this is your case.


Some quick testing: I created a project from Web API template using ASP .NET Core 2.0 and modified the first action in the controller it created:

// GET api/values
[HttpGet]
public IEnumerable<string> Get(CancellationToken cancelToken)
{
    Thread.Sleep(7000);
    cancelToken.ThrowIfCancellationRequested(); // breakpoint here
    return new string[] { "value1", "value2" };
}

Hit F5. It starts the app (including Kestrel) with IIS Express in front of it. Make the request and abort it (by closing a browser tab) before the 7 seconds. cancelToken.IsCancellationRequested is false when the breakpoint triggers.

Now, change the debug profile from IIS Express to WebApplication1 (or whatever it is called):

enter image description here

Everything works as expected for me.

I did also try the same with ASP .NET Core 1.1 but with no success.


AFAIK with ASP .NET Core 2.0, one should be able to use Kestrel on its own. I don't know if Apache or Nginx are doing better than IIS.

like image 165
Lukas Z. Avatar answered Sep 26 '22 09:09

Lukas Z.