Как обрабатывать операции async в Startup.Configure?
В моем приложении ASP.NET 5 я хочу загрузить некоторые данные из Azure в кеш внутри моего метода Startup.Configure. Azure SDK предоставляет только асинхронные методы. Как правило, вызов метода async выполняется через ожидание внутри асинхронного метода, например:
public async Task Configure(IApplicationBuilder app, IMemoryCache cache)
{
Data dataToCache = await DataSource.LoadDataAsync();
cache.Set("somekey", dataToCache);
// remainder of Configure method omitted for clarity
}
Однако ASP.NET 5 требует, чтобы метод Configure возвращал void. Я мог бы использовать метод async void, но я понимаю, что методы async void должны использоваться только для обработчиков событий (согласно https://msdn.microsoft.com/en-us/magazine/jj991977.aspx среди многих других).
Я думал, что лучший способ сделать это - это вызвать функцию async без ожидания, вызвать Wait из возвращенной задачи, а затем кешировать результаты с помощью свойства Task.Results, например:
public void Configure(IApplicationBuilder app, IMemoryCache cache)
{
Task<Data> loadDataTask = DataSource.LoadDataAsync();
loadDataTask.Wait();
cache.Set("somekey", loadDataTask.Result);
// remainder of Configure method omitted for clarity
}
Стивен Вальтер использовал аналогичный подход в сообщении в начале этого года. Однако это неясно из этой должности, если это считается приемлемой практикой. Это?
Если это считается приемлемой практикой, что - если есть - обработка ошибок мне нужна? Мое понимание заключается в том, что Task.Wait() будет перебрасывать любые исключения, вызванные операцией async, и я не предоставил никакого механизма для отмены операции async. Просто вызывается Task.Wait() достаточно?
Ответы
Ответ 1
В примере кода в блоге, с которым вы связались, использовался только sync-over-async, чтобы заполнить базу данных примерами данных; этот вызов не будет существовать в производственном приложении.
Во-первых, я бы сказал, что если вам действительно нужно Configure
быть асинхронным, тогда вы должны поднять проблему с командой ASP.NET, чтобы она была на их радаре. Было бы не слишком сложно для них добавить поддержку ConfigureAsync
в этот момент (то есть до выпуска).
Во-вторых, у вас есть несколько подходов к проблеме. Вы можете использовать task.Wait
(или, еще лучше, task.GetAwaiter().GetResult()
, что позволяет избежать обертки AggregateException
, если ошибка возникает). Или вы можете кэшировать задачу, а не результат задачи (которая работает, если IMemoryCache
- это скорее словарь, чем какая-то странная операция сериализации в двоичном массиве в памяти - я смотрю на вас, предыдущий версии ASP.NET).
Если это считается приемлемой практикой, что - если есть - обработка ошибок мне нужна?
Использование GetAwaiter().GetResult()
приведет к тому, что исключение (если оно есть) распространится из Configure
. Я не уверен, как ответ ASP.NET будет, если конфигурация приложения не удалась.
Я не предоставил никакого механизма для отмены операции async.
Я не уверен, как вы можете "отменить" настройку приложения, поэтому я не стал бы беспокоиться об этой части.
Ответ 2
Вы можете выполнить некоторую асинхронную работу, но этот метод является синхронным, и вы не можете его изменить. Это означает, что вам нужно синхронно ждать завершения асинхронных вызовов.
Вы не хотите возвращаться из метода Startup, если запуск еще не закончен, правильно? Ваше решение кажется все в порядке.
Что касается обработки исключений: если часть работы, с которой ваше приложение не может работать нормально, вы должны позволить сбой метода Startup (см. Fail-fast). Если это не что-то важное, я бы включил соответствующую часть в блок catch try и просто зарегистрировал проблему для последующего контроля.