I thought it would be a good idea to use CancellationToken
in my controller like so:
[HttpGet("things", Name = "GetSomething")]
public async Task<ActionResult> GetSomethingAsync(CancellationToken ct) {
var result = await someSvc.LoadSomethingAsync(ct);
return Ok(result);
}
The issue is that now Azure Application Insights shows a bunch of exceptions of type System.Threading.Tasks.TaskCancelledException: A Task was canceled.
as well as the occasional Npgsql.PostgresException: 57014: canceling statement due to user request
. This is noise that I don't need.
Application Insights is registered as a service using the standard method - services.AddApplicationInsightsTelemetry(Configuration);
.
I thought I could jack into the application pipeline and catch the above Exceptions, converting them to normal Responses. I put the code below in various places. It catches any exceptions and if IsCancellationRequested, it returns a dummy response. Otherwise it rethrows the caught exception.
app.Use(async (ctx, next) =>
{
try { await next(); }
catch (Exception ex)
{
if (ctx.RequestAborted.IsCancellationRequested)
{
ctx.Response.StatusCode = StatusCodes.Status418ImATeapot;
}
else { throw; }
}
});
This code works in that it changes the response. However exceptions are still getting sent to Application Insights.
RequestAborted.IsCancellationRequested
over trying to catch specific exceptions. The reason being that if I've already discovered one implementation that throws an exception not derived from OperationCanceledException
the possibility exists there are others that will do the same.I wish I understood Application Insights mechanism of reporting exceptions. After experimenting I feel like trying to catch errors in the Application pipeline isn't the correct approach. I just don't know what is.
I was able to solve this issue with a TelemetryProcessor.
In order to get access to RequestAborted.IsCancellationRequested in the processor, the HttpContext service needed to be made available by calling services.AddHttpContextAccessor()
in Startup.ConfigureServices.
In the processor I prevent any exception telemetry from being processed if IsCancellationRequested is true. Below is a simplified example of my final solution, as eventually I realized I needed to do some more nuanced work with Dependencies and Requests that are out of scope of my original request.
internal class AbortedRequestTelemetryProcessor : ITelemetryProcessor
{
private readonly IHttpContextAccessor httpContextAccessor;
private readonly ITelemetryProcessor next;
public AbortedRequestTelemetryProcessor(
ITelemetryProcessor next, IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
this.next = next;
}
public void Process(ITelemetry item)
{
if (httpContextAccessor.HttpContext?.RequestAborted.IsCancellationRequested == true
&& item is ExceptionTelemetry)
{
// skip exception telemetry if cancellation was requested
return;
}
// Send everything else:
next.Process(item);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With