Search code examples
c#asp.net-core.net-coredependency-injectionrequest-cancelling

AddScoped dependency with a CancellationToke


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?


Solution

  • 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)
    {
    }