public async Task <IHttpActionResult> UpdateProduct([FromBody] ItemCatalog product)
        {
            var item = _catalogContext.ItemCatalogs.FirstOrDefault(i => i.ID == product.ID);

            if (ModelState.IsValid)
            {
                _catalogContext.ItemCatalogs.Add(item);
                _catalogContext.SaveChanges();

                var oldPrice = item.ItemValue;
                item.ItemValue = product.ItemValue;
                _catalogContext.ItemCatalogs.Add(item);
                var @event = new ProductPriceChangedIntegrationEvent(item.ID,
                                                                     item.ItemValue,
                                                                     oldPrice);

                _eventBus.Publish(@event);
                return(Ok(item));
            }
            else
            {
                return(BadRequest());

                throw new HttpResponseException(HttpStatusCode.PaymentRequired);
            }
        }
示例#2
0
        public async Task UpdateProductAsync(CatalogItem productToUpdate)
        {
            //TODO: checking for necessity of publishing event PriceChanged
            //TODO: Other possibilities for state of event is not considered
            //To update the price of a product and guarantee consistency,
            //(that the publishing of it's related event has definitely happened after persisting in current service,
            //first we need to update CatalogContext(and product)
            //and we need to store details of the related event in database (IntegrationEventLogContext)
            //IN THE SAME TRANSACTION
            //then we will publish the event
            //and if everything goes as expected, we change the state of event to published in db
            //TODO don't send productToUpdate to repo. fetch the current object, change it's price then send it (if fetched in admin panel before update there is no problem
            var oldPrice = _catalogContext.CatalogItems.AsNoTracking().Single(e => e.Id == productToUpdate.Id).Price;

            if (oldPrice != productToUpdate.Price)
            {
                ProductPriceChangedIntegrationEvent evt =
                    new ProductPriceChangedIntegrationEvent(productToUpdate.Id, productToUpdate.Price, oldPrice);
                using (var transaction = _catalogContext.Database.BeginTransaction())
                {
                    _catalogContext.CatalogItems.Update(productToUpdate);
                    await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(evt);

                    transaction.Commit();
                }

                _eventBus.Publish(evt);
                await _integrationEventLogService.MarkEventAsPublished(evt.Id);
            }
            else
            {
                _catalogContext.CatalogItems.Update(productToUpdate);
                _catalogContext.SaveChanges();
            }
        }
示例#3
0
        public async Task <IActionResult> UpdateProduct([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound());
            }
            var raiseProductPriceChangedEvent = catalogItem.Price != productToUpdate.Price;
            var oldPrice = catalogItem.Price;

            // Update current product
            catalogItem = productToUpdate;
            _catalogContext.CatalogItems.Update(catalogItem);

            if (raiseProductPriceChangedEvent) // Save and publish integration event if price has changed
            {
                //Create Integration Event to be published through the Event Bus
                var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);

                // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
                await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent);

                // Publish through the Event Bus and mark the saved event as published
                await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
            }
            else // Save updated product
            {
                await _catalogContext.SaveChangesAsync();
            }

            return(Ok());
        }
        public async Task <IActionResult> UpdateProduct([FromBody] CatalogItem item)
        {
            var @event = new ProductPriceChangedIntegrationEvent(item.ProductId, item.NewPrice, item.OldPrice);

            _eventBus.Publish(@event);
            return(Ok(@event));
        }
示例#5
0
        public async Task <ActionResult> UpdateProductAsync([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogRepository.GetAsync(productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound(new { Message = $"Item with id {productToUpdate.Id} not found." }));
            }

            var oldPrice = catalogItem.Price;
            var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;

            catalogItem = productToUpdate;

            if (raiseProductPriceChangedEvent)
            {
                var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
                _eventBus.Publish(priceChangedEvent);
                await _catalogRepository.UpdateItemAsync(catalogItem);
            }
            else
            {
                await _catalogRepository.UpdateItemAsync(catalogItem);
            }

            return(CreatedAtAction(nameof(ItemByIdAsync), new { id = productToUpdate.Id }, null));
        }
        public async Task <ActionResult> UpdateProductAsync([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound(new { Message = $"Item with id {productToUpdate.Id} not found." }));
            }

            var oldPrice = catalogItem.Price;
            var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;

            // Update current product
            catalogItem = productToUpdate;
            _catalogContext.CatalogItems.Update(catalogItem);

            if (raiseProductPriceChangedEvent) // Save product's data and publish integration event through the Event Bus if price has changed
            {
                //Create Integration Event to be published through the Event Bus
                var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);

                // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
                await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent);

                // Publish through the Event Bus and mark the saved event as published
                await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
            }
            else // Just save the updated product because the Product's Price hasn't changed.
            {
                await _catalogContext.SaveChangesAsync();
            }

            return(CreatedAtAction(nameof(ItemByIdAsync), new { id = productToUpdate.Id }, null));
        }
示例#7
0
        public async Task Handle_BasketHasProductWithOldPrice_UpdateUnitPrice(
            [Frozen] Mock <IBasketRepository> mockBasketRepository,
            ProductPriceChangedIntegrationEventHandler sut,
            ProductPriceChangedIntegrationEvent productPriceChangedEvent,
            string user1,
            string user2
            )
        {
            //Arrange
            mockBasketRepository.Setup(_ => _.GetUsers())
            .Returns(new string[] { user1, user2 });

            var basket_user1 = new CustomerBasket
            {
                Items = new List <BasketItem>
                {
                    new BasketItem
                    {
                        ProductNumber = productPriceChangedEvent.ProductNumber,
                        UnitPrice     = productPriceChangedEvent.OldPrice
                    }
                }
            };

            var basket_user2 = new CustomerBasket
            {
                Items = new List <BasketItem>
                {
                    new BasketItem
                    {
                        ProductNumber = productPriceChangedEvent.ProductNumber,
                        UnitPrice     = productPriceChangedEvent.OldPrice
                    }
                }
            };

            mockBasketRepository.Setup(_ => _.GetBasketAsync(It.Is <string>(_ => _ == user1)))
            .ReturnsAsync(basket_user1);

            mockBasketRepository.Setup(_ => _.GetBasketAsync(It.Is <string>(_ => _ == user2)))
            .ReturnsAsync(basket_user2);

            //Act
            await sut.Handle(productPriceChangedEvent);

            //Assert
            mockBasketRepository.Verify(_ => _.UpdateBasketAsync(
                                            It.Is <CustomerBasket>(_ => _ == basket_user1)
                                            ));

            mockBasketRepository.Verify(_ => _.UpdateBasketAsync(
                                            It.Is <CustomerBasket>(_ => _ == basket_user2)
                                            ));

            basket_user1.Items[0].UnitPrice.Should().Be(productPriceChangedEvent.NewPrice);
            basket_user1.Items[0].OldUnitPrice.Should().Be(productPriceChangedEvent.OldPrice);

            basket_user2.Items[0].UnitPrice.Should().Be(productPriceChangedEvent.NewPrice);
            basket_user2.Items[0].OldUnitPrice.Should().Be(productPriceChangedEvent.OldPrice);
        }
示例#8
0
        public async Task Handle_BasketDoesNotHaveProduct_BasketNotUpdated(
            [Frozen] Mock <IBasketRepository> mockBasketRepository,
            ProductPriceChangedIntegrationEventHandler sut,
            ProductPriceChangedIntegrationEvent productPriceChangedEvent,
            string user1,
            CustomerBasket basket
            )
        {
            //Arrange
            mockBasketRepository.Setup(_ => _.GetUsers())
            .Returns(new string[] { user1 });

            mockBasketRepository.Setup(_ => _.GetBasketAsync(It.Is <string>(_ => _ == user1)))
            .ReturnsAsync(basket);

            //Act
            await sut.Handle(productPriceChangedEvent);

            //Assert
            mockBasketRepository.Verify(_ => _.UpdateBasketAsync(
                                            It.IsAny <CustomerBasket>()
                                            ),
                                        Times.Never
                                        );
        }
示例#9
0
        public async Task <IActionResult> UpdateProduct([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogContext.CatalogItems
                              .SingleOrDefaultAsync(c => c.Id == productToUpdate.Id);

            if (null == catalogItem)
            {
                return(NotFound(new { Message = $"未找到ID为{productToUpdate.Id}的目录项" }));
            }

            var oldPrice = catalogItem.Price;
            var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;

            //更新当前产品
            catalogItem = productToUpdate;
            _catalogContext.CatalogItems.Update(catalogItem);
            //价格改变,保存和发布事件。
            if (raiseProductPriceChangedEvent)
            {
                //创建价格改变事件
                var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
                //保存目录数据和事件发布日志--此步骤需要通过本地事务保证原子性。
                await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent);

                //发布事件
                await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
            }
            else
            {
                await _catalogContext.SaveChangesAsync();
            }

            return(CreatedAtAction(nameof(GetItemById), new { id = productToUpdate.Id }, null));
        }
示例#10
0
        public async Task <IActionResult> UpdateProduct([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogContext.CatalogItems
                              .SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound(new { Message = $"Item with id {productToUpdate.Id} not found." }));
            }

            var oldPrice = catalogItem.Price;
            var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;


            // Update current product
            catalogItem = productToUpdate;
            _catalogContext.CatalogItems.Update(catalogItem);

            if (raiseProductPriceChangedEvent) // Save and publish integration event if price has changed
            {
                //Create Integration Event to be published through the Event Bus
                var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);

                // Publish through the Event Bus
                await _endpoint.Publish(priceChangedEvent);
            }
            else // Save updated product
            {
                await _catalogContext.SaveChangesAsync();
            }

            return(CreatedAtAction(nameof(GetItemById), new { id = productToUpdate.Id }, null));
        }
示例#11
0
        public IActionResult IsAlive()
        {
            var priceChangedEvent = new ProductPriceChangedIntegrationEvent(1, 10, 12);

            _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
            return(this.NoContent());
        }
        public async Task <IActionResult> UpdateProduct([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound());
            }

            bool             raiseProductPriceChangedEvent = false;
            IntegrationEvent priceChangedEvent             = null;

            if (catalogItem.Price != productToUpdate.Price)
            {
                raiseProductPriceChangedEvent = true;
            }

            if (raiseProductPriceChangedEvent) // Create event if price has changed
            {
                var oldPrice = catalogItem.Price;
                priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
            }

            //Update current product
            catalogItem = productToUpdate;

            //Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
            //See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
            var strategy        = _catalogContext.Database.CreateExecutionStrategy();
            var eventLogService = _integrationEventLogServiceFactory(_catalogContext.Database.GetDbConnection());
            await strategy.ExecuteAsync(async() =>
            {
                // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
                using (var transaction = _catalogContext.Database.BeginTransaction())
                {
                    _catalogContext.CatalogItems.Update(catalogItem);
                    await _catalogContext.SaveChangesAsync();

                    //Save to EventLog only if product price changed
                    if (raiseProductPriceChangedEvent)
                    {
                        await eventLogService.SaveEventAsync(priceChangedEvent, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
                    }

                    transaction.Commit();
                }
            });


            //Publish to Event Bus only if product price changed
            if (raiseProductPriceChangedEvent)
            {
                _eventBus.Publish(priceChangedEvent);
                await eventLogService.MarkEventAsPublishedAsync(priceChangedEvent);
            }

            return(Ok());
        }
示例#13
0
        public async Task <IActionResult> CheckoutBasketAsync([FromBody] BasketCheckoutDto basketCheckout)
        {
            try
            {
                var basket = await _basketRepository.GetBasketById(basketCheckout.BasketId);

                if (basket == null)
                {
                    return(BadRequest());
                }
                BasketCheckoutMessage basketCheckoutMessage = _mapper.Map <BasketCheckoutMessage>(basketCheckout);
                basketCheckoutMessage.BasketLines = new List <BasketLineMessage>();
                int total = 0;
                foreach (var b in basket.BasketLines)
                {
                    var basketLineMessage = new BasketLineMessage
                    {
                        BasketLineId = b.BasketLineId,
                        Price        = b.Price,
                        TicketAmount = b.TicketAmount
                    };
                    total += b.Price * b.TicketAmount;
                    basketCheckoutMessage.BasketLines.Add(basketLineMessage);
                }
                Discount discount = null;
                if (basket.DiscountId.HasValue)
                {
                    discount = await _discountService.GetDiscount(basket.DiscountId.Value);
                }
                if (discount != null)
                {
                    basketCheckoutMessage.BasketTotal = total - discount.Amount;
                }
                else
                {
                    basketCheckoutMessage.BasketTotal = total;
                }

                try
                {
                    ProductPriceChangedIntegrationEvent queueData = new ProductPriceChangedIntegrationEvent
                                                                        (basketCheckoutMessage.BasketId, basketCheckoutMessage.BasketTotal, basketCheckoutMessage.UserId);
                    _eventBus.Publish(queueData);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
                await _basketRepository.ClearBasket(basketCheckout.BasketId);

                return(Accepted(basketCheckoutMessage));
            }
            catch (Exception e)
            {
                return(StatusCode(StatusCodes.Status500InternalServerError, e.StackTrace));
            }
        }
示例#14
0
        public ActionResult SimulatePriceChange(string productId, [FromQuery] decimal newPrice)
        {
            var @event = new ProductPriceChangedIntegrationEvent(productId, newPrice);

            // Publish integration event to the event bus
            // (RabbitMQ or a service bus underneath)
            _eventBus.Publish(@event);
            return(Ok());
        }
示例#15
0
        public ActionResult <IEnumerable <CatalogItem> > Get()
        {
            var priceChangedEvent = new ProductPriceChangedIntegrationEvent(1, 34, 55);

            _eventBus.Publish(priceChangedEvent);
            var result = _catalogContext.CatalogItems.ToList();

            return(result);
        }
示例#16
0
        public async Task <ActionResult> UpdateProductAsync([FromBody] CatalogItem productToUpdate)
        {
            var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound(new { Message = $"Item with id {productToUpdate.Id} not found." }));
            }

            var oldPrice = catalogItem.Price;
            var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;

            // Update current product
            catalogItem = productToUpdate;
            _catalogContext.CatalogItems.Update(catalogItem);

            if (raiseProductPriceChangedEvent) // Save product's data and publish integration event through the Event Bus if price has changed
            {
                _logger.LogInformation(" [x] CatalogController.UpdateProduct(): Price has changed, integration event is being prepared...");

                var productPriceChangeEvent = new ProductPriceChangedIntegrationEvent(productToUpdate.Id,
                                                                                      oldPrice, productToUpdate.Price);

                var strategy = _catalogContext.Database.CreateExecutionStrategy();
                _logger.LogInformation(" [x] CatalogController.UpdateProductAsync(): Beginning new transaction to save event and commit changes.");
                await strategy.Execute(async() => {
                    using (var transaction = _catalogContext.Database.BeginTransaction())
                    {
                        await _eventLogService.SaveEventAsync(productPriceChangeEvent, transaction);
                        await _catalogContext.SaveChangesAsync();
                        transaction.Commit();
                        _logger.LogInformation(" [x] CatalogController.UpdateProductAsync(): Transaction ({0}) has been committed.", transaction.TransactionId);
                    }
                });

                try
                {
                    await _eventLogService.MarkEventAsInProgressAsync(productPriceChangeEvent.Id);

                    _eventBus.Publish(productPriceChangeEvent);
                    await _eventLogService.MarkEventAsPublishedAsync(productPriceChangeEvent.Id);
                }

                catch (Exception e)
                {
                    _logger.LogError(e, " [x] CatalogController.UpdateProductAsync(): Fail when publishing integration event {0}.", productPriceChangeEvent.Id);
                    await _eventLogService.MarkEventAsFailedAsync(productPriceChangeEvent.Id);
                }
            }
            else // Just save the updated product because the Product's Price hasn't changed.
            {
                await _catalogContext.SaveChangesAsync();
            }

            return(Ok());
        }
示例#17
0
        public async Task <ActionResult> UpdateProductAsync([FromBody] CatalogItem productToUpdate, [FromServices] ICapPublisher capBus)
        {
            var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

            if (catalogItem == null)
            {
                return(NotFound(new { Message = $"Item with id {productToUpdate.Id} not found." }));
            }

            var oldPrice = catalogItem.Price;
            var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;

            catalogItem = productToUpdate;

            // Save product's data and publish integration event through the Event Bus if price has changed
            if (raiseProductPriceChangedEvent)
            {
                var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
                var curTransaction    = _catalogContext.Database.BeginTransaction(capBus);
                try
                {
                    _catalogContext.CatalogItems.Update(catalogItem);
                    //publish integration event
                    capBus.Publish(nameof(ProductPriceChangedIntegrationEvent), priceChangedEvent);
                    await _catalogContext.SaveChangesAsync();

                    curTransaction.Commit();
                }
                catch
                {
                    try
                    {
                        curTransaction?.Rollback();
                    }
                    finally
                    {
                        curTransaction?.Dispose();
                    }
                    throw;
                }
                finally
                {
                    curTransaction?.Dispose();
                }
            }
            else // Just save the updated product because the Product's Price hasn't changed.
            {
                _catalogContext.CatalogItems.Update(catalogItem);
                await _catalogContext.SaveChangesAsync();
            }

            return(CreatedAtAction(nameof(ItemByIdAsync), new { id = productToUpdate.Id }, null));
        }
        public async Task Handle(ProductPriceChangedIntegrationEvent @event)
        {
            using (LogContext.PushProperty("IntegrationEventContext", $"{Program.AppName}"))
            {
                _logger.LogInformation("----- Handling integration event: {AppName} - ({@IntegrationEvent})", Program.AppName, @event);

                var userIds = _repository.GetUsers();

                foreach (var id in userIds)
                {
                    var basket = await _repository.GetBasketAsync(id);

                    await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
                }
            }
        }
示例#19
0
        public async Task Handle(ProductPriceChangedIntegrationEvent @event)
        {
            var users = await repository.GetAllUsersAsync();

            foreach (var Id in users)
            {
                var basket = await repository.GetBasketAsync(Id);

                //TODO SingleOrDefault or Where?
                var item = basket.Items.SingleOrDefault(x => x.ProductId == @event.ProductId);
                if (item != null)
                {
                    item.UnitPrice = @event.NewPrice;
                    item.OldPrice  = @event.OldPrice;
                }
                await repository.UpdateBasketAsync(basket);
            }
        }
        public async Task <IActionResult> PutCatalogItem(int id, CatalogItem productToUpdate)
        {
            if (id != productToUpdate.Id)
            {
                return(BadRequest());
            }


            try
            {
                var catalogItem = await _context.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);

                var oldPrice = catalogItem.Price;
                var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;

                if (raiseProductPriceChangedEvent)
                {
                    var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
                    catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
                }
                _context.Entry(productToUpdate).State = EntityState.Modified;

                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CatalogItemExists(id))
                {
                    return(NotFound());
                }
                else
                {
                    throw;
                }
            }

            return(NoContent());
        }
示例#21
0
        public void Change_Price_Integration_Event()
        {
            var @event = new ProductPriceChangedIntegrationEvent("SKU-1234", 25, 17);

            _service.PublishThroughEventBusAsync(@event);
        }
示例#22
0
        public void EventBusTry([FromServices] IEventBus _eventBus, int blogId = 1)
        {
            var piblishEvent = new ProductPriceChangedIntegrationEvent(blogId); //声明事件源

            _eventBus.Publish(piblishEvent);                                    //发布事件
        }
        public async Task <IActionResult> UpdateProductAsync(string id, [FromBody] ProductViewModel updateModel,
                                                             CancellationToken cancellationToken)
        {
            try
            {
                var item = await _catalogContext.Products
                           .Include(x => x.ProductImages)
                           .Include(x => x.ProductColors)
                           .SingleOrDefaultAsync(i => i.Id == id, cancellationToken);

                if (item == null)
                {
                    return(NotFound(new { Message = $"Item with id {updateModel.Id} not found." }));
                }

                if (updateModel.CategoryId <= 0 || updateModel.ManufacturerId <= 0)
                {
                    return(BadRequest(new
                    {
                        Message = $"Cant update Product when category and manufacturer is not assign."
                    }));
                }
                if (updateModel.ProductImages == null || updateModel.ProductImages.Length <= 0)
                {
                    return(BadRequest(new { Message = "Cant update product with 0 image" }));
                }

                var oldPrice = item.Price;
                var raiseProductPriceChangedEvent = oldPrice != updateModel.Price;

                updateModel.Id = id;

                #region Clean all Images and colors

                _catalogContext.ProductImages.RemoveRange(item.ProductImages);
                _catalogContext.ProductColors.RemoveRange(item.ProductColors);

                // Delete Previous Images
                foreach (var image in item.ProductImages)
                {
                    _fileUtility.DeleteFile("ProductImage/" + id, image.ImageName);
                }

                // Insert new images
                foreach (var image in updateModel.ProductImages)
                {
                    await InsertProductImageAsync(updateModel, cancellationToken, image);
                }

                await _catalogContext.SaveChangesAsync(cancellationToken);

                #endregion

                #region Mapping
                // Update current product
                item.Description    = updateModel.Description;
                item.LastUpdatedBy  = updateModel.ActorId;
                item.LastUpdated    = DateTime.Now;
                item.Name           = updateModel.Name;
                item.CategoryId     = updateModel.CategoryId;
                item.ManufacturerId = updateModel.ManufacturerId;
                item.Price          = updateModel.Price;
                item.ProductImages  = updateModel.ProductImages.Select(x =>
                                                                       new ProductImage {
                    ImageName = x.ImageName, ImageUrl = x.ImageUrl, ProductId = x.ProductId
                })
                                      .ToList();
                item.ProductColors = updateModel.ProductColors
                                     .Select(x => new ProductColor {
                    Name = x.Name, ProductId = x.ProductId
                }).ToList();

                #endregion

                // Update current product
                _catalogContext.Products.Update(item);


                if (raiseProductPriceChangedEvent) // Save product's data and publish integration event through the Event Bus if price has changed
                {
                    //Create Integration Event to be published through the Event Bus
                    var priceChangedEvent = new ProductPriceChangedIntegrationEvent(item.Id, updateModel.Price, oldPrice);

                    // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
                    await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(0, "PriceChanged", priceChangedEvent);

                    // Publish through the Event Bus and mark the saved event as published
                    await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
                }
                else // Just save the updated product because the Product's Price hasn't changed.
                {
                    await _catalogContext.SaveChangesAsync(cancellationToken);
                }

                return(CreatedAtAction(nameof(UpdateProductAsync), new
                {
                    id = item.Id
                }, null));
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }