Centralised approach to set request timeout? - c#

On my controllers actions, I can insert a CancellationToken parameter and the platform will fill it so I can implement cooperative cancellation. How can I configure this token? I would like to set its timeout to 10sec for example (pref in a global middleware)

Related

How can I find out where CancellationToken is being cancelled?

I have a very weird case where my ASP.NET Core Web API endpoint fails randomly due to CancellationToken being cancelled. I have that problem only when I run integration tests, the API works completely fine when I call it from Postman.
In order to understand what's going on, I'd like to know what causes the CancellationToken to have its state set to cancelled. Is there any way to enable some logging for that or any other solution?
The CancellationToken comes from the ASP.Net Core Web API action, it's created by the framework iteself.
// EDIT
Here's my action:
public async Task<ActionResult<TokenResponse>> GetToken(
[Required][FromBody] Parameters parameters,
ApiVersion apiVersion,
CancellationToken cancellationToken) { ... }
My application just passes that token through various layers.
From pure technical standpoint you can leverage cancelation callback (if you are the owner of CancellationTokenSource do not forget to call TryReset on it in case it is reused). For example:
CancellationToken cancellationToken = ...;
cancellationToken.Register(() => throw new Exception("Here")); // exception with stack trace will be thrown
Though not sure that this information will be as useful as you possibly expect.

How to get the value of properties from Serilog Enrichers inside a controller method

I have an ASP.NET Web API project that uses Serilog with the Correlation Id enricher. It works fine for HTTP requests, but I have a few controller endpoints that queue a job for a dedicated async worker to handle when it's free (using Microsoft.Extensions.Hosting.IHostedService). The issue is since these jobs get picked up outside of the initial HTTP request block, they lose the Correlation Id. I know I can push a property to the Logger Context using:
Serilog.Context.LogContext.PushProperty("CorrelationId", request.CorrelationId);
But I'm unsure how to get the existing correlation id that's used in the initial HTTP request. If I do, I can send it in the job metadata to be used with the async jobs later. Any ideas?

How does a request cancellation token actually get marked for cancellation?

I'm looking for some more information on what actually causes IsCancellationRequested to become set for a cancellation token.
I see plenty of articles and videos stating to just throw the token in a httpClient.PostAsync() call and then we can check the property of IsCancellationRequested on the token that we pass in and do our cancellation processing if it's requested. I also see that we can use the token source to call cancel for it as well.
My confusion here is around me sending a request to an endpoint that I own and what triggers the IsCancellationRequested property to become set as true on my response. Will this become set as true on any exception thrown? And is this only possible to set as true on an exception being thrown? I don't full understand the role the server has in requesting a cancellation.

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

Why the 404 middleware behaves like this? [duplicate]

I've been trying to understand how ASP.NET 5 pipeline middlewares really work. A middleware, as I know, is just a Func<RequestDelegate, RequestDelegate>, which is a pointer to a method that receives a reference to the next request delegate and returns a new one that wraps the next. We can of course, use a class to represent a middleware, something like:
public class MyMiddleware
{
private readonly _next;
public MyMiddleware(RequestDelegate next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
_next = next;
}
public Task Invoke(HttpContext context)
{
// New request delegate code here which can wrap the next one on the pipeline
}
}
Since the RequestDelegate is a delegate that can hold references to methods which receives one HttpContext and returns a Task the Invoke method is the request delegate to be returned and which has access to the next one on the pipeline.
We have then, when coding a middleware, access to the next component of the pipeline, but there is a doubt I have. In the beginning I thought the ideal was always to work the following way:
Check if the middleware can handle the request
If it can, do whatever must be done with the HttpContext
Call the next middleware on the pipeline
So that when I studied this for the first time I thought each middleware should always call the next one. But doing this led to strange behavior as discussed on this question.
Also looking at the source code of some middlewares I see some of them follow another steps:
Check if the middleware can handle the request
If it can, do whatever must be done with the HttpContext and that's all
If not, and only if not call the next one
Is this the real idea of using middlewares? Which way is the correct approach at this? Each middleware do what must be done with the request and always invoke the next or if a midleware can handle the request it doesn't invoke the next anymore?
I believe a middleware should call the next only if it can't handle the request. The reason I think that is because if not, there would be coupling between the middlewares on the pipeline. So that to process the request the middleware would need to be aware of what the previous one did to avoid messing everything. Is this conclusion right?
Middleware exist to make the request pipeline modular, meaning that you can add/remove/replace parts from it as long as you respect the contract. For example, if your application serves some files without any caching, you can add a middleware at the front of the pipeline without altering the rest. They are building blocks.
A middleware can:
Do nothing and pass the request further (e.g. a middleware that is applicable only to POST requests but the current one is GET)
Do nothing to the request, do something else instead and pass it further (e.g. logging)
Do something to the request and pass the request further (e.g. get an authentication token and convert it to an identity, or remove some sensitive information from the request)
End the pipeline and not pass the request further (e.g. StaticFileMiddleware which just returns the file, or MVC when a route matches)
Probably answering your other question too: there are two types of middleware:
Middleware that are designed to do something and pass the data along further (etc. auth, cookies, validation, logging etc)
Middleware that complete the pipeline (static file, MVC, etc).
Of course, some might do both depending on the context. For example auth can end the pipeline if the credentials are incorrect but continue otherwise.
The author of the middleware must decide if the next middleware (if any) should be invoked. In the case of the middleware in your question which returns a message, it should not invoke the next one.

Categories