#c_sharp #архитектура #aspnet_web_api #async_await
Мы никогда не использовали async/await (или что-то подобное) в нашем небольшом проекте. Но сейчас проект растет, и мы решили добавить асинхронность. Проект имеет следующую архитектуру: Domain (репозиторий, EF) UnitTests Service (новый, тут планируется перенести бизнес логику с контроллеров) WebUI Мой вопрос, в каком слое мы должны реализовать асинхронность? Или мы должны сделать это на нескольких слоях? Пожалуйста, подскажите мне, где реализация будет наиболее подходящей? Например у меня есть метод в контроллере public virtual HttpResponseMessage Get() { var entity = Repository.GetAll(); if (entity != null && entity.Any()) { return Request.CreateResponse(HttpStatusCode.OK, entity); } var message = $"{GenericTypeName}: No content"; return ErrorMsg(HttpStatusCode.NoContent, message); } Как мне сделать его асинхронным?
Ответы
Ответ 1
class Repository { public TaskGetAllAsync(CancellationToken cancellationToken) { return Task.Run (() => { // тут что-то ресурсоёмкое вычисляем return entity; // возвращаем результат }); } } Второй пример, то же самое только с async await class Repository { public async Task GetAllAsync(CancellationToken cancellationToken) { // вернёт управление в вызывающий код await Task.Yield(); // тут что-то ресурсоёмкое вычисляем return entity; // возвращаем результат } } Третий пример, если нужно перед возвратом данных вычислить, что-то параллельно class Repository { public async Task GetAllAsync(CancellationToken cancellationToken) { var tasks = new List (); tasks.Add(Task.Run (() => { // тут что-то ресурсоёмкое вычисляем return entity; // возвращаем результат })); tasks.Add(Task.Run (() => { // тут что-то ресурсоёмкое вычисляем return entity; // возвращаем результат })); tasks.Add(Task.Run (() => { // тут что-то ресурсоёмкое вычисляем return entity; // возвращаем результат })); // дожидаемся окончания всех задач await Task.WhenAll(tasks); // дальше пробегаемся по списку задач, получаем результат работы каждой и что-то с ним делаем. И возвращаем уже вычисленный нами результат. } } Конечно в реальном боевом приложении код будет немного другой и зависеть от конкретной задачи но принцип будет один и тот же. Обращаю внимание, что async/await это синтаксическая обёртка над Task.Run с некоторыми отличиями. А отличия в обработке исключений в процессе выполнения задачи. Но прежде чем писать асинхронный код обязательно прочитайте про async/await И task иначе будет множество ошибок. Особенно внимательно нужно смотреть обработку исключений. Ответ 2
Асинхронность распространяется на все слои. От нижнего к верхнему. В вашем случае, если Domain асинхронный то и WebUI будет асинхронным. Не забывайте, что асинхронность нужна только для операций с периферийными устройствами (диск, сеть...) для того, что бы при ожидании ответа не простаивал рабочий поток. class Repository { public TaskGetAllAsync(CancellationToken cancellationToken) { using (var db = new DataContext()) { return db.EntitySet.ToListAsync(); } } } public virtual async Task Get(CancellationToken cancellationToken) { var entity = await Repository.GetAllAsync(cancellationToken); if (!entity.Any()) { var message = $"{GenericTypeName}: No content"; return Content(HttpStatusCode.NoContent, message); } return Ok(entity); } Обратите внимание http status code 204 - No content (это не ошибочный статус код) Для справки: https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP И вообще вам прежде нужно почитать про Task и async await. Task.Run используется для cpu bound operations (Вычислительных операций процессора) async await для ожидания результата этих операций в вызывающем коде или ожидания операций I/O bound operations. То что касается entity framework то в 6 версии есть асинхронные методы их названия заканчиваются на Async, например .ToListAsync().
Комментариев нет:
Отправить комментарий