/// <remarks> /// Конечно же, если выберется такая проверка, то её лучше вынести в отдельный сервис, потому-что контроллер не должен /// быть таким умным и многофункциональным. /// Тут баланс между скоростью работы сервиса IFiguresStorage/ его нагруженностью / средним колличеством позиций /// Ну и если позиций мало, сервис работает быстро, то этот метод лучше не использовать, так как генерация исключения /// операция не дешёвая /// </remarks> // TODO: вынести в отлельный сервис private bool AreAllPositionsAvailableFast(Cart cart, out Position badPosition) { var cts = new CancellationTokenSource(); Position badPositionLocal = null; try { cart.Positions.AsParallel().WithCancellation(cts.Token).ForAll(position => { // Если нашли недоступную позицию - отменяем все проверки (неплохо бы добавить CancellationToken и в IFiguresStorage) if (!_figuresStorage.CheckIfAvailable(position.Type, position.Count)) { badPositionLocal = position; cts.Cancel(); } }); } catch (OperationCanceledException) { return(false); } catch (AggregateException e) { // Что-то пошло не так рушим всё и сразу // Перед тем как пробросить эксепшен - логируем _logger.Log(LogLevel.Error, e, e.Message); // Именно так, чтобы сохранить полный stack trace throw; } finally { badPosition = badPositionLocal; cts.Dispose(); } return(true); }
public async Task <decimal> OrderFigures(Cart cart) { Order order = new Order { Positions = cart.Positions.Select(x => new OrderFigure(x)).ToList() }; order.Positions.ForEach(x => x.Figure.Validate()); cart.Positions.ForEach(x => { if (_figuresStorage.CheckIfAvailable(x.Type, x.Count)) { throw new FigureNotAvailableException(); } }); cart.Positions.ForEach(x => _figuresStorage.Reserve(x.Type, x.Count)); return(await _orderStorage.Save(order)); }