#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 я не должен заботиться о клиентском коде. Совершенно верно. Предоставьте возможность клиенту самому решать, когда ему запускать метод синхронно, а когда -- асинхронно. Создание асинхронных оберток для синхронных методов мы уже обсуждали.
Комментариев нет:
Отправить комментарий