|
@ -1,9 +1,6 @@ |
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
|
|
|
|
|
|
using Catalog.API.IntegrationEvents; |
|
|
|
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
using Microsoft.EntityFrameworkCore; |
|
|
using Microsoft.EntityFrameworkCore; |
|
|
using Microsoft.EntityFrameworkCore.Storage; |
|
|
|
|
|
using Microsoft.EntityFrameworkCore.Infrastructure; |
|
|
|
|
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; |
|
|
|
|
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; |
|
|
|
|
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; |
|
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; |
|
|
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; |
|
|
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; |
|
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Model; |
|
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Model; |
|
@ -11,12 +8,8 @@ using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel; |
|
|
using Microsoft.Extensions.Options; |
|
|
using Microsoft.Extensions.Options; |
|
|
using System; |
|
|
using System; |
|
|
using System.Collections.Generic; |
|
|
using System.Collections.Generic; |
|
|
using System.Data.Common; |
|
|
|
|
|
using System.Linq; |
|
|
using System.Linq; |
|
|
using System.Threading.Tasks; |
|
|
using System.Threading.Tasks; |
|
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; |
|
|
|
|
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities; |
|
|
|
|
|
using Catalog.API.IntegrationEvents; |
|
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
{ |
|
|
{ |
|
@ -24,16 +17,16 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
public class CatalogController : ControllerBase |
|
|
public class CatalogController : ControllerBase |
|
|
{ |
|
|
{ |
|
|
private readonly CatalogContext _catalogContext; |
|
|
private readonly CatalogContext _catalogContext; |
|
|
private readonly IOptionsSnapshot<Settings> _settings; |
|
|
|
|
|
|
|
|
private readonly CatalogSettings _settings; |
|
|
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService; |
|
|
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService; |
|
|
|
|
|
|
|
|
public CatalogController(CatalogContext Context, IOptionsSnapshot<Settings> settings, ICatalogIntegrationEventService catalogIntegrationEventService) |
|
|
|
|
|
|
|
|
public CatalogController(CatalogContext context, IOptionsSnapshot<CatalogSettings> settings, ICatalogIntegrationEventService catalogIntegrationEventService) |
|
|
{ |
|
|
{ |
|
|
_catalogContext = Context; |
|
|
|
|
|
_catalogIntegrationEventService = catalogIntegrationEventService; |
|
|
|
|
|
_settings = settings; |
|
|
|
|
|
|
|
|
_catalogContext = context ?? throw new ArgumentNullException(nameof(context)); |
|
|
|
|
|
_catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService)); |
|
|
|
|
|
|
|
|
((DbContext)Context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; |
|
|
|
|
|
|
|
|
_settings = settings.Value; |
|
|
|
|
|
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
|
|
|
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
|
|
@ -46,19 +39,37 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
.LongCountAsync(); |
|
|
.LongCountAsync(); |
|
|
|
|
|
|
|
|
var itemsOnPage = await _catalogContext.CatalogItems |
|
|
var itemsOnPage = await _catalogContext.CatalogItems |
|
|
.OrderBy(c=>c.Name) |
|
|
|
|
|
|
|
|
.OrderBy(c => c.Name) |
|
|
.Skip(pageSize * pageIndex) |
|
|
.Skip(pageSize * pageIndex) |
|
|
.Take(pageSize) |
|
|
.Take(pageSize) |
|
|
.ToListAsync(); |
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
itemsOnPage = ComposePicUri(itemsOnPage); |
|
|
|
|
|
|
|
|
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); |
|
|
|
|
|
|
|
|
var model = new PaginatedItemsViewModel<CatalogItem>( |
|
|
var model = new PaginatedItemsViewModel<CatalogItem>( |
|
|
pageIndex, pageSize, totalItems, itemsOnPage); |
|
|
|
|
|
|
|
|
pageIndex, pageSize, totalItems, itemsOnPage); |
|
|
|
|
|
|
|
|
return Ok(model); |
|
|
return Ok(model); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
[HttpGet] |
|
|
|
|
|
[Route("items/{id:int}")] |
|
|
|
|
|
public async Task<IActionResult> GetItemById(int id) |
|
|
|
|
|
{ |
|
|
|
|
|
if (id <= 0) |
|
|
|
|
|
{ |
|
|
|
|
|
return BadRequest(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var item = await _catalogContext.CatalogItems.SingleOrDefaultAsync(ci => ci.Id == id); |
|
|
|
|
|
if (item != null) |
|
|
|
|
|
{ |
|
|
|
|
|
return Ok(item); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return NotFound(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// GET api/v1/[controller]/items/withname/samplename[?pageSize=3&pageIndex=10]
|
|
|
// GET api/v1/[controller]/items/withname/samplename[?pageSize=3&pageIndex=10]
|
|
|
[HttpGet] |
|
|
[HttpGet] |
|
|
[Route("[action]/withname/{name:minlength(1)}")]
|
|
|
[Route("[action]/withname/{name:minlength(1)}")]
|
|
@ -75,7 +86,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
.Take(pageSize) |
|
|
.Take(pageSize) |
|
|
.ToListAsync(); |
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
itemsOnPage = ComposePicUri(itemsOnPage); |
|
|
|
|
|
|
|
|
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); |
|
|
|
|
|
|
|
|
var model = new PaginatedItemsViewModel<CatalogItem>( |
|
|
var model = new PaginatedItemsViewModel<CatalogItem>( |
|
|
pageIndex, pageSize, totalItems, itemsOnPage); |
|
|
pageIndex, pageSize, totalItems, itemsOnPage); |
|
@ -108,7 +119,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
.Take(pageSize) |
|
|
.Take(pageSize) |
|
|
.ToListAsync(); |
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
itemsOnPage = ComposePicUri(itemsOnPage); |
|
|
|
|
|
|
|
|
itemsOnPage = ChangeUriPlaceholder(itemsOnPage); |
|
|
|
|
|
|
|
|
var model = new PaginatedItemsViewModel<CatalogItem>( |
|
|
var model = new PaginatedItemsViewModel<CatalogItem>( |
|
|
pageIndex, pageSize, totalItems, itemsOnPage); |
|
|
pageIndex, pageSize, totalItems, itemsOnPage); |
|
@ -138,16 +149,23 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
return Ok(items); |
|
|
return Ok(items); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//POST api/v1/[controller]/update
|
|
|
|
|
|
[Route("update")] |
|
|
|
|
|
[HttpPost] |
|
|
|
|
|
|
|
|
//PUT api/v1/[controller]/items
|
|
|
|
|
|
[Route("items")] |
|
|
|
|
|
[HttpPut] |
|
|
public async Task<IActionResult> UpdateProduct([FromBody]CatalogItem productToUpdate) |
|
|
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 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 oldPrice = catalogItem.Price; |
|
|
|
|
|
|
|
|
|
|
|
var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Update current product
|
|
|
// Update current product
|
|
|
catalogItem = productToUpdate; |
|
|
catalogItem = productToUpdate; |
|
|
_catalogContext.CatalogItems.Update(catalogItem); |
|
|
_catalogContext.CatalogItems.Update(catalogItem); |
|
@ -156,40 +174,40 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
{ |
|
|
{ |
|
|
//Create Integration Event to be published through the Event Bus
|
|
|
//Create Integration Event to be published through the Event Bus
|
|
|
var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice); |
|
|
var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
|
|
|
// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
|
|
|
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent); |
|
|
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Publish through the Event Bus and mark the saved event as published
|
|
|
// Publish through the Event Bus and mark the saved event as published
|
|
|
await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); |
|
|
await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); |
|
|
} |
|
|
} |
|
|
else // Save updated product
|
|
|
else // Save updated product
|
|
|
{ |
|
|
{ |
|
|
await _catalogContext.SaveChangesAsync(); |
|
|
await _catalogContext.SaveChangesAsync(); |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return Ok(); |
|
|
|
|
|
|
|
|
return CreatedAtAction(nameof(GetItemById), new { id = productToUpdate.Id }, null); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//POST api/v1/[controller]/create
|
|
|
|
|
|
[Route("create")] |
|
|
|
|
|
|
|
|
//POST api/v1/[controller]/items
|
|
|
|
|
|
[Route("items")] |
|
|
[HttpPost] |
|
|
[HttpPost] |
|
|
public async Task<IActionResult> CreateProduct([FromBody]CatalogItem product) |
|
|
public async Task<IActionResult> CreateProduct([FromBody]CatalogItem product) |
|
|
{ |
|
|
{ |
|
|
_catalogContext.CatalogItems.Add( |
|
|
|
|
|
new CatalogItem |
|
|
|
|
|
{ |
|
|
|
|
|
CatalogBrandId = product.CatalogBrandId, |
|
|
|
|
|
CatalogTypeId = product.CatalogTypeId, |
|
|
|
|
|
Description = product.Description, |
|
|
|
|
|
Name = product.Name, |
|
|
|
|
|
PictureUri = product.PictureUri, |
|
|
|
|
|
Price = product.Price |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
var item = new CatalogItem |
|
|
|
|
|
{ |
|
|
|
|
|
CatalogBrandId = product.CatalogBrandId, |
|
|
|
|
|
CatalogTypeId = product.CatalogTypeId, |
|
|
|
|
|
Description = product.Description, |
|
|
|
|
|
Name = product.Name, |
|
|
|
|
|
PictureUri = product.PictureUri, |
|
|
|
|
|
Price = product.Price |
|
|
|
|
|
}; |
|
|
|
|
|
_catalogContext.CatalogItems.Add(item); |
|
|
|
|
|
|
|
|
await _catalogContext.SaveChangesAsync(); |
|
|
await _catalogContext.SaveChangesAsync(); |
|
|
|
|
|
|
|
|
return Ok(); |
|
|
|
|
|
|
|
|
return CreatedAtAction(nameof(GetItemById), new { id = item.Id }, null); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//DELETE api/v1/[controller]/id
|
|
|
//DELETE api/v1/[controller]/id
|
|
@ -202,16 +220,19 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers |
|
|
if (product == null) |
|
|
if (product == null) |
|
|
{ |
|
|
{ |
|
|
return NotFound(); |
|
|
return NotFound(); |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
_catalogContext.CatalogItems.Remove(product); |
|
|
_catalogContext.CatalogItems.Remove(product); |
|
|
|
|
|
|
|
|
await _catalogContext.SaveChangesAsync(); |
|
|
await _catalogContext.SaveChangesAsync(); |
|
|
|
|
|
|
|
|
return Ok(); |
|
|
|
|
|
|
|
|
return NoContent(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private List<CatalogItem> ComposePicUri(List<CatalogItem> items) { |
|
|
|
|
|
var baseUri = _settings.Value.ExternalCatalogBaseUrl; |
|
|
|
|
|
|
|
|
private List<CatalogItem> ChangeUriPlaceholder(List<CatalogItem> items) |
|
|
|
|
|
{ |
|
|
|
|
|
var baseUri = _settings.ExternalCatalogBaseUrl; |
|
|
|
|
|
|
|
|
items.ForEach(x => |
|
|
items.ForEach(x => |
|
|
{ |
|
|
{ |
|
|
x.PictureUri = x.PictureUri.Replace("http://externalcatalogbaseurltobereplaced", baseUri); |
|
|
x.PictureUri = x.PictureUri.Replace("http://externalcatalogbaseurltobereplaced", baseUri); |
|
|