#c_sharp #многопоточность #async_await #асинхронность
Есть вот такой класс из слоя бизнес-логики: public class ProductService { private readonly IGenericRepository_productRepository; public ProductService(IGenericRepository productRepository) { _productRepository = productRepository; } public Task Update(int id, ProductModel model) { return Task.Run(() => { if (model == null) { throw new ArgumentNullException(nameof(model)); } var product = _productRepository.GetById(id); if (product == null) { throw new ArgumentException(nameof(id)); } // еще код... // _productRepository.Update(product); }); } } Я поймал себя на том, что у меня все методы, обращающиеся к базе данных (даже если они обращаются через репозитории), возвращают Task, так как знаю, что выше у меня Web API контроллер, action которого я хочу вызывать асинхронно. Я думаю, что я делаю неправильно, потому что, проектируя класс ProductService я не должен заботиться о клиентском коде. Сейчас да, у меня клиентом является самый верхний слой (Web API), но так ведь может быть не всегда и для другого клиента возможно тип Task метода Update может быть излишним. Я прав? Согласно своим рассуждениям я переписал методProductService.Update() и класс-клиент: public void Update(int id, ProductModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } var product = _productRepository.GetById(id); if (product == null) { throw new ArgumentException(nameof(id)); } // еще код... // _productRepository.Update(product); } [RoutePrefix("api/products")] public class ProductsController : ApiController { private readonly IProductService _productService; public ProductsController(IProductService productService) { _productService = productService; } [HttpPut] [Route("{id:int}")] public async Task Put([FromBody] productModel) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var productId = (int)RequestContext.RouteData.Values["id"]; await Task.Run(() => { _productService.Update(productId, productModel); }); return Ok(); }
Ответы
Ответ 1
В том что вы делаете, нет ни малейшего смысла - методы контроллеров уже исполняются в пуле потоков, и выносить их снова в пул потоков через Task.Run - бесполезно. Если вам хочется сделать полностью асинхронный код - надо отказаться от Task.Run в пользу действительно асинхронных способов. Так, если вы используете EntityFramework, то вытащить запись из БД можно через FirstOrDefaultAsync, а сохранить изменения - через SaveChangesAsyncОтвет 2
Я думаю, что я делаю неправильно, потому что, проектируя класс ProductService я не должен заботиться о клиентском коде. Совершенно верно. Предоставьте возможность клиенту самому решать, когда ему запускать метод синхронно, а когда -- асинхронно. Создание асинхронных оберток для синхронных методов мы уже обсуждали.
Комментариев нет:
Отправить комментарий