2

I have a .NET core dependency that is scoped to each REST API request. It is added in Startup.ConfigureServices with a call to AddScoped.

I want to add cancellation support to this. If I add a CancellationToken cancellationToken to any controller action's parameters I can get a token that is cancelled if the client-side request is. I can then pass that token to all the methods on my dependency.

However, the dependency is scoped to the request, so passing the token down through the action to the methods feels unnecessary - could I just add the CancellationToken to the scoped dependency somehow?

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Keith
  • 150,284
  • 78
  • 298
  • 434
  • Possible duplicate of https://stackoverflow.com/questions/64122616/cancellation-token-injection – Métoule Oct 05 '20 at 08:52
  • @Métoule possibly, though that question appears to be asking about the general case (i.e. transient and static scopes too) and I think that may mean it can't be done. I am specifically asking for the more narrow `AddScoped` case - my injected dependency exists for exactly the same scope that cancellation token applies to. – Keith Oct 05 '20 at 09:26
  • It's not unnecessary. Cancellation tokens are there to cancel an action in progress (i.e. a long running loop) prematurely) and is independent of the scope, so it may still be useful to stop the request as soon as possible and free up the request. The request may be cancelled for multiple reasons, such as connection loss, user accidentally clicking the link twice in fas succession in the browser or hitting ESC while the page is loading – Tseng Oct 05 '20 at 09:38
  • @Tseng yes, and there could be use cases that need to pass the cancellation token for their specific scope. However, here connection loss, user repeating or aborting the request are all in the same scope - those aren't different tokens to .NET, they are all HTTP cancellations that will look the same to the action. The scopes are identical. – Keith Oct 05 '20 at 10:27

1 Answers1

5

could I just add the CancellationToken to the scoped dependency somehow?

Well, technically yes. i.e. by injecting IHttpAccessorand accessing HttpContext.RequestAborted property, which is the same cancellation token you usually get passed into the controllers action if defined.

But using the action parameter overload is actually kinda discouraged as in every controller action you can access the cancellation token via HttpContext.RequestAborted and having it in controllers action kinda makes the token public, i.e. when creating Swagger scheme (at least was the case back in 2017), where as using the HttpContext itself didn't expose it to the public.

The only exception to that seems to be, when using "Poco Controllers" which don't inherit from Controller or ControllerBase and not injecting IHttpAccessor into this controller.

But injecting cancellation tokens into arbitrary services is problematic as you get a hard dependency on the web framework (IHttpAccessor/HttpContext).

It's best and cleanest to keep having a CancellationToken parameter on your methods which can be cancelled in a meaningful way and make the token optional, so you can only pass the parameter in situation where you have a request or a situation that can be cancelled

public Task<Result> ProcessSomething(string param1, CancellationToken cancellationToken = default)
{
}
Tseng
  • 61,549
  • 15
  • 193
  • 205
  • So instead of a cancellation token in the action parameters I should have `var cancellationToken = this.HttpContext.RequestAborted;` and in my `Startup.ConfigureServices` I should do `services.AddScoped(provider => new CancelableImpl(provider.GetService()?.HttpContext?.RequestAborted ?? default)`? – Keith Oct 05 '20 at 10:43
  • @Keith: Well no. Actually the best way is to take cancellation tokens as method parameters for operations that can be canceled, since at some point any of your services is called up from the controller at one point or another. That the ones that aren't also don't need the http request cancellation token for obvious reasons – Tseng Jul 30 '21 at 08:58