исключения - Как безопасно вызывать метод async на C#без ожидания




try catch exception c# (4)

У меня есть метод async который не возвращает данных:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

Я вызываю это из другого метода, который возвращает некоторые данные:

public string GetStringData()
{
    MyAsyncMethod(); // this generates a warning and swallows exceptions
    return "hello world";
}

Вызов MyAsyncMethod() не ожидая его, вызывает « Поскольку этот вызов не ожидается, текущий метод продолжает выполняться до завершения вызова » предупреждение в visual studio. На странице этого предупреждения указано:

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

Я уверен, что не хочу дождаться завершения звонка; Мне не нужно или есть время. Но вызов может вызвать исключения.

Я несколько раз наткнулся на эту проблему, и я уверен, что это общая проблема, которая должна иметь общее решение.

Как безопасно вызывать метод асинхронизации, не ожидая результата?

Обновить:

Для людей, предлагающих, что я просто жду результата, это код, который отвечает на веб-запрос в нашем веб-сервисе (ASP.NET Web API). В ожидании контекста пользовательского интерфейса поддерживает поток пользовательского интерфейса, но ожидание вызова веб-запроса будет ждать завершения задачи перед ответом на запрос, тем самым увеличивая время ответа без причины.


Вы должны сначала подумать о том, чтобы GetStringData использовать метод async и MyAsyncMethod задачу, возвращенную из MyAsyncMethod .

Если вы абсолютно уверены, что вам не нужно обрабатывать исключения из MyAsyncMethod или знать, когда они завершатся, вы можете сделать это:

public string GetStringData()
{
  var _ = MyAsyncMethod();
  return "hello world";
}

Кстати, это не «общая проблема». Очень редко нужно выполнять какой-то код и не заботиться о том, завершает ли он и не заботится, успешно ли он завершается.

Обновить:

Поскольку вы на ASP.NET и хотите вернуться раньше, вы можете найти мое сообщение в блоге по теме полезной . Однако ASP.NET не был разработан для этого, и нет гарантии, что ваш код будет запущен после ответа ответа. ASP.NET сделает все возможное, чтобы запустить его, но он не может этого гарантировать.

Таким образом, это прекрасное решение для чего-то простого, например, для передачи события в журнал, где это не имеет большого значения, если вы потеряете несколько здесь и там. Это нехорошее решение для любых бизнес-критических операций. В этих ситуациях вы должны использовать более сложную архитектуру с постоянным способом сохранения операций (например, Azure Queues, MSMQ) и отдельный фоновый процесс (например, роль рабочего места Azure, служба Win32) для их обработки.


Думаю, возникает вопрос: зачем вам это нужно? Причина async в C # 5.0 заключается в том, что вы можете ждать результата. Этот метод на самом деле не асинхронный, а просто вызываемый одновременно, чтобы не мешать слишком большому потоку текущего потока.

Возможно, лучше начать нить и оставить ее закончить самостоятельно.


Ответ Peter Ritchie был тем, что я хотел, и статья Стивена Клири о возвращении на раннем этапе ASP.NET была очень полезна.

Однако, как более общая проблема (не специфичная для контекста ASP.NET), следующее консольное приложение демонстрирует использование и поведение ответа Питера с помощью Task.ContinueWith(...)

static void Main(string[] args)
{
  try
  {
    // output "hello world" as method returns early
    Console.WriteLine(GetStringData());
  }
  catch
  {
    // Exception is NOT caught here
  }
  Console.ReadLine();
}

public static string GetStringData()
{
  MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted);
  return "hello world";
}

public static async Task MyAsyncMethod()
{
  await Task.Run(() => { throw new Exception("thrown on background thread"); });
}

public static void OnMyAsyncMethodFailed(Task task)
{
  Exception ex = task.Exception;
  // Deal with exceptions here however you want
}

GetStringData() возвращается раньше, не ожидая MyAsyncMethod() и исключения, которые были MyAsyncMethod() в MyAsyncMethod() , рассматриваются в OnMyAsyncMethodFailed(Task task) а не в try / catch вокруг GetStringData()


Я получаю это решение:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

public string GetStringData()
{
    // Run async, no warning, exception are catched
    RunAsync(MyAsyncMethod()); 
    return "hello world";
}

private void RunAsync(Task task)
{
    task.ContinueWith(t =>
    {
        ILog log = ServiceLocator.Current.GetInstance<ILog>();
        log.Error("Unexpected Error", t.Exception);

    }, TaskContinuationOptions.OnlyOnFaulted);
}




async-await