Запустить и забыть асинхронный метод в asp.net mvc

Общие ответы, такие какВот а такжеВот вогонь и забыть вопросы не использовать async / await, а использоватьTask.Run или жеTaskFactory.StartNew вместо этого передается синхронный метод.

Тем не менее, иногда метод, который я хочуогонь и забыть является асинхронным, и нет эквивалентного метода синхронизации.

Обновление Примечание / Предупреждение: Как отметил Стивен Клири ниже, опасно продолжать работу над запросом после того, как вы отправите ответ. Причина в том, что AppDomain может быть закрыт, пока эта работа еще продолжается. Смотрите ссылку в своем ответе для получения дополнительной информации. В любом случае, я просто хотел указать на это заранее, чтобы я неникого не отправьте по неверному пути.

Я думаю, что мой случай действителен, потому что фактическая работа выполняется другой системой (другой компьютер на другом сервере), поэтому мне нужно только знать, что сообщение осталось для этой системы. Если есть исключение, то сервер или пользователь ничего не может с этим поделать, и это не влияет на пользователя, все, что мне нужно сделать, - это обратиться к журналу исключений и очистить вручную (или реализовать какой-то автоматизированный механизм). Если AppDomain будет закрыт, у меня будет остаточный файл в удаленной системе, но я выберу его как часть моего обычного цикла обслуживания, и так как его существование больше не известно моему веб-серверу (базе данных), и его имя уникально отметка времени, это не вызовет никаких проблем, в то время как это все еще задерживается.

Было бы идеально, если бы у меня был доступ к постоянному механизму, как указал Стивен Клири, но, к сожалению, я нет в это время.

Я подумал, просто притворившись, что запрос DeleteFoo завершился нормально на стороне клиента (javascript), при этом оставив запрос открытым, но мне нужна информация в ответе, чтобы продолжить, так что он бы все выдержал.

Итак, оригинальный вопрос ...

например:

//External library
public async Task DeleteFooAsync();

В моем коде mvc asp.net я хочу вызвать DeleteFooAsync в стиле «забыл и забыл» - я нене хочу задерживать ответ, ожидающий завершения DeleteFooAsync. Если по какой-либо причине происходит сбой DeleteFooAsync (или возникает исключение), пользователь или программа ничего не могут с этим поделать, поэтому я просто хочу записать ошибку.

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

//In my code
Task deleteTask = DeleteFooAsync()

//In my App_Start
TaskScheduler.UnobservedTaskException += ( sender, e ) =>
{
    m_log.Debug( "Unobserved exception! This exception would have been unobserved: {0}", e.Exception );
    e.SetObserved();
};

Есть ли риски в этом?

Другой вариант, о котором я могу подумать, - сделать свою собственную обертку, такую как:

private void async DeleteFooWrapperAsync()
{
    try
    {
        await DeleteFooAsync();
    }
    catch(Exception exception )
    {
        m_log.Error("DeleteFooAsync failed: " + exception.ToString());
    }
}

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

Мой вопрос заключается в том, что это правильный способ вызвать асинхронный метод в режиме "забыл и забыл"?

ОБНОВИТЬ:

Ну, я обнаружил, что в моем контроллере следующее (не то, что действие контроллера должно быть асинхронным, потому что есть другие ожидающие асинхронные вызовы):

[AcceptVerbs( HttpVerbs.Post )]
public async Task DeleteItemAsync()
{
    Task deleteTask = DeleteFooAsync();
    ...
}

вызвал исключение из формы:

Необработанное исключение: System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта. в System.Web.ThreadContext.AssociateWithCurrentThread (BooleansetImpersonationContext)

Это обсуждаетсяВот и, кажется, связано с SynchronizationContext и 'возвращенная задача была переведена в состояние терминала до завершения всех асинхронных работ '.

Итак, единственный метод, который работал:

Task foo = Task.Run( () => DeleteFooAsync() );

Я понимаю, почему это работает, потому что StartNew получает новый поток для DeleteFooAsync для работы.

К сожалению, СкоттПриведенное ниже предложение не работает для обработки исключений в этом случае, потому что foo больше не является задачей DeleteFooAsync, а является задачей Task.Run, поэтому не обрабатывает исключения из DeleteFooAsync. Моя UnobservedTaskException в конце концов вызывается, так что, по крайней мере, это все еще работает.

Итак, я думаю, что вопрос все еще стоит, как вы можете запустить асинхронный метод в asp.net mvc?

Ответы на вопрос(3)

Ваш ответ на вопрос