Остановить исключение, генерируемое CancellationToken от получения Reported by ApplicationInsights - PullRequest
5 голосов
/ 30 октября 2019

I думал было бы неплохо использовать CancellationToken в моем контроллере следующим образом:

[HttpGet("things", Name = "GetSomething")]
public async Task<ActionResult> GetSomethingAsync(CancellationToken ct) {
    var result = await someSvc.LoadSomethingAsync(ct);
    return Ok(result);
}

Проблема в том, что теперь Azure Application Insights отображает кучу исключенийтипа System.Threading.Tasks.TaskCancelledException: A Task was canceled., а также случайные Npgsql.PostgresException: 57014: canceling statement due to user request. Это шум, который мне не нужен.

Application Insights регистрируется как сервис с использованием стандартного метода - services.AddApplicationInsightsTelemetry(Configuration);.

Попытка решения

Я думал, что смогувставьте в конвейер приложения и перехватите вышеуказанные исключения, преобразовав их в обычные ответы. Я поместил код ниже в разных местах. Он перехватывает любые исключения и, если IsCancellationRequested, возвращает фиктивный ответ. В противном случае он перебрасывает перехваченное исключение.

app.Use(async (ctx, next) =>
{
    try { await next(); }
    catch (Exception ex)
    {
        if (ctx.RequestAborted.IsCancellationRequested)
        {       
            ctx.Response.StatusCode = StatusCodes.Status418ImATeapot;
        }
        else { throw; }
    }
});

Этот код работает в том смысле, что он изменяет ответ. Однако исключения по-прежнему отправляются в Application Insights.

Требования

  • Я хотел бы иметь решение, использующее RequestAborted.IsCancellationRequested вместо попытки отловить определенные исключения. Причина в том, что, если я уже обнаружил одну реализацию, которая выдает исключение, не полученное из OperationCanceledException, существует вероятность, что есть другие, которые будут делать то же самое.
  • Не имеет значения, если ошибки зависимости все еще получаютне регистрируется, только то, что исключения, сгенерированные в результате отмены запроса, не выполняются.
  • Я не хочу использовать try / catch в каждом методе контроллера. Его нужно разместить в одном месте.

Заключение

Хотелось бы, чтобы я понял механизм Application Insights, сообщающий об исключениях. После экспериментов я чувствую, что попытка отловить ошибки в конвейере приложений - неправильный подход. Я просто не знаю, что это такое.

Ответы [ 2 ]

0 голосов
/ 14 ноября 2019

Мне удалось решить эту проблему с помощью TelemetryProcessor .

Чтобы получить доступ к RequestAborted.IsCancellationRequested в процессоре, HttpContextУслугу необходимо сделать доступной, позвонив по номеру services.AddHttpContextAccessor() в Startup.ConfigureServices .

В процессоре я запрещаю обработку любой исключительной телеметрии, если IsCancellationRequested правда. Ниже приведен упрощенный пример моего окончательного решения, поскольку в конце концов я понял, что мне нужно выполнить более тонкую работу с зависимостями и запросами, которые выходят за рамки моего исходного запроса.

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);
    }
}
0 голосов
/ 11 ноября 2019

Вы пытались создать ExceptionFilter?

public class MyExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        if (context?.Exception.Message == "Did it catch this?")
        {
            context.Result = new BadRequestObjectResult("You have no access.");
        }
    }
}

Внутри метода ConfigureServices:

services.AddMvc(config =>
        {
            config.Filters.Add(typeof(MyExceptionFilter));
        })

Логика внутри фильтра просто для того, чтобы дать вам пример того, как выхочу что-то фильтровать и распространять результат. В вашем случае, я думаю, вам нужно как-то проглотить исключение, привязанное к контексту, чтобы потом не было обнаружено исключение.

Возможно, просто присвоение ему значения null поможет?

...