Асинхронная операция все еще ожидала при использовании метода расширения задачи с await - PullRequest
0 голосов
/ 11 января 2019

Я прочитал сообщение в блоге от Джона Тириета о создании метода "Забей и забудь". Я реализовал его метод расширения, хотя при его использовании я получаю ошибку.

Пример кода ниже:

    public async Task<ActionResult> Index()
    {
      /* 
        a lot of work here 
        some sync services called, some awaits to async services
       */

        // here I wanted to call logging service using "fire and forget",
        // because I don't really care about it, 
        // and I don't need to wait for it to show the page for user
        _logService.LogAsync(obj).FireAndForgetSafeAsync();
        return RedirectToAction("Summary");
    }

Метод из этого поста следующий:

public static class TaskUtilities
{
#pragma warning disable RECS0165 // Asynchronous methods should return a Task instead of void
    public static async void FireAndForgetSafeAsync(this Task task, IErrorHandler handler = null)
#pragma warning restore RECS0165 // Asynchronous methods should return a Task instead of void
    {
        try
        {
            await task;
        }
        catch (Exception ex)
        {
            handler?.HandleError(ex);
        }
    }
}

И код делает An asynchronous module or handler completed while an asynchronous operation was still pending исключение. Я знаю, что это из-за кода регистрации, но я не уверен, почему. Когда я делаю try catch внутри Index с await LogAsync, он работает нормально (также работает «медленная» отладка). Как можно обрабатывать этот код для правильной работы? Можем ли мы создать такой метод расширения, чтобы сделать некоторую операцию «запустить и забыть» в контроллере, ожидая других методов? Может кто-нибудь объяснить мне, что на самом деле не так и почему это не работает? Симилар темы не помогли мне объяснить мою проблему. Спасибо.

1 Ответ

0 голосов
/ 12 января 2019

Если в вашем журнале регистрации событий «забыл и забыл» используется какой-либо контекст конвейера (например, если вы регистрируете строку запроса вызывающего абонента), вы ДОЛЖНЫ дождаться вызова регистрации, где-нибудь, до завершения HTTP-запроса. В противном случае контекст может исчезнуть, прежде чем он будет зарегистрирован, когда ASP.NET разрушит конвейер, созданный для запроса. Вот почему ASP.NET дает вам эту ошибку, чтобы защитить вас от себя.

Если ваш код ведения журнала «забыл и забыл» НЕ использует какой-либо контекст конвейера (например, он получает доступ только к данным, предоставленным ему в аргументах), то вы можете разрешить ему запускаться после завершения конвейера, используя QueueBackgroundWorkItem.

См. Также этот ответ .

...