From 34043afa6bfdb5328a33deac074a8aa8ea253f5c Mon Sep 17 00:00:00 2001 From: Unai Date: Mon, 31 Oct 2016 16:54:55 +0100 Subject: [PATCH 1/5] Review project. Update packages. Fix Http api --- .../Controllers/CatalogController.cs | 75 ++++++------------- src/Services/Catalog/Catalog.API/Dockerfile | 2 +- .../Catalog.API/Model/CatalogContext.cs | 41 +++++++--- .../Catalog.API/Model/CatalogContextSeed.cs | 67 +++++++++++++++++ .../Catalog/Catalog.API/Model/CatalogItem.cs | 21 +++--- src/Services/Catalog/Catalog.API/Program.cs | 1 + src/Services/Catalog/Catalog.API/Startup.cs | 57 +++++++++++--- src/Services/Catalog/Catalog.API/project.json | 18 +++-- ...ettings.json => settings.development.json} | 2 +- .../Catalog.API/settings.production.json | 11 +++ 10 files changed, 203 insertions(+), 92 deletions(-) create mode 100644 src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs rename src/Services/Catalog/Catalog.API/{settings.json => settings.development.json} (61%) create mode 100644 src/Services/Catalog/Catalog.API/settings.production.json diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index f703c2944..ccb218a0d 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -1,72 +1,45 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.eShopOnContainers.Services.Catalog.API.Model; - + namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers { - [Route("/")] + using Microsoft.AspNetCore.Mvc; + using Microsoft.EntityFrameworkCore; + using Microsoft.eShopOnContainers.Services.Catalog.API.Model; + using System; + using System.Linq; + using System.Threading.Tasks; + + [Route("api/v1/[controller]")] public class CatalogController : ControllerBase { - private CatalogContext _context; + private readonly CatalogContext _context; public CatalogController(CatalogContext context) { _context = context; } - // GET api/values - [HttpGet] - public IEnumerable Get() - { - return _context.CatalogItems.ToList(); - } + // GET api/v1/[controller]/all - // GET api/values/5 - [HttpGet("{id}")] - public IActionResult Get(Guid id) + [HttpGet] + [Route("[action]")] + public async Task All() { - var item = _context.CatalogItems.FirstOrDefault(x=> x.Id == id); - - if(item == null) - { - return NotFound(); - } + var items = await _context.CatalogItems + .ToListAsync(); - return new OkObjectResult(item); + return Ok(items); } - // POST api/values - [HttpPost] - public IActionResult Post([FromBody]CatalogItem item) - { - try - { - _context.CatalogItems.Add(item); - _context.SaveChanges(); - return Ok(); - } - catch - { - return StatusCode(500, "Unable to add new catalog item"); - } - } + // GET api/v1/[controller]/FindByName/samplename - // PUT api/values/5 - [HttpPut("{id}")] - public IActionResult Put(int id, [FromBody]CatalogItem item) + [HttpGet] + [Route("FindByName/{name:minlength(1)}")] + public async Task Find(string name) { - _context.CatalogItems.Update(item); - _context.SaveChanges(); - return Ok(); - } + var items = await _context.CatalogItems + .Where(c => c.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase)) + .ToListAsync(); - // DELETE api/values/5 - [HttpDelete("{id}")] - public IActionResult Delete(Guid id) - { return Ok(); } } diff --git a/src/Services/Catalog/Catalog.API/Dockerfile b/src/Services/Catalog/Catalog.API/Dockerfile index 99490a7c3..3e3ef42e8 100644 --- a/src/Services/Catalog/Catalog.API/Dockerfile +++ b/src/Services/Catalog/Catalog.API/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore +FROM microsoft/aspnetcore:latest WORKDIR /app EXPOSE 80 ADD . /app diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs index c8fa53cf6..dc78bce84 100644 --- a/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs +++ b/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs @@ -1,15 +1,12 @@ -using Microsoft.EntityFrameworkCore; -using Npgsql.EntityFrameworkCore.PostgreSQL; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model { + using EntityFrameworkCore.Metadata.Builders; + using Microsoft.EntityFrameworkCore; + using Npgsql.EntityFrameworkCore.PostgreSQL; + public class CatalogContext : DbContext { - public CatalogContext(DbContextOptions options): base(options) + public CatalogContext(DbContextOptions options) : base(options) { } @@ -17,7 +14,33 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model protected override void OnModelCreating(ModelBuilder builder) { + builder.HasSequence("idseq") + .StartsAt(1) + .IncrementsBy(1); + + builder.Entity(ConfigureCatalogItem); + builder.HasPostgresExtension("uuid-ossp"); } + + void ConfigureCatalogItem(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalog"); + + builder.Property(ci => ci.Id) + .HasDefaultValueSql("nextval('idseq')") + .IsRequired(); + + builder.Property(ci => ci.Name) + .IsRequired(true) + .HasMaxLength(50); + + builder.Property(ci => ci.Price) + .IsRequired(true); + + builder.Property(ci => ci.PictureUri) + .IsRequired(false); + + } } } diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs new file mode 100644 index 000000000..a941dc165 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs @@ -0,0 +1,67 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model +{ + using Microsoft.AspNetCore.Builder; + using Model; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class CatalogContextSeed + { + public static async Task SeedAsync(IApplicationBuilder applicationBuilder) + { + var context = (CatalogContext)applicationBuilder + .ApplicationServices.GetService(typeof(CatalogContext)); + + using (context) + { + context.Database.EnsureCreated(); + + if (!context.CatalogItems.Any()) + { + context.CatalogItems.AddRange( + GetPreconfiguredItems()); + + await context.SaveChangesAsync(); + } + } + } + + static IEnumerable GetPreconfiguredItems() + { + return new List() + { + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" } + + }; + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs b/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs index abc3f91af..b79f7bd1a 100644 --- a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs +++ b/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs @@ -1,20 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model { + using System; + public class CatalogItem { - public CatalogItem() - { - } + public int Id { get; set; } - public Guid Id { get; set; } public string Name { get; set; } + public string Description { get; set; } + public decimal Price { get; set; } - public int ImageCount { get; set; } + + public string PictureUri { get; set; } + + public CatalogItem() { } } } diff --git a/src/Services/Catalog/Catalog.API/Program.cs b/src/Services/Catalog/Catalog.API/Program.cs index 82ca9383e..1eaf35596 100644 --- a/src/Services/Catalog/Catalog.API/Program.cs +++ b/src/Services/Catalog/Catalog.API/Program.cs @@ -14,6 +14,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API { var host = new WebHostBuilder() .UseKestrel() + .UseUrls(Environment.GetEnvironmentVariable("ASPNETCORE_URLS") ?? String.Empty) .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() .Build(); diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 80485de5d..08a0baafb 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -1,48 +1,81 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.eShopOnContainers.Services.Catalog.API.Model; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.eShopOnContainers.Services.Catalog.API.Model; -using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json.Serialization; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Catalog.API { public class Startup { + public IConfigurationRoot Configuration { get; } + public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) - .AddJsonFile("settings.json") + .AddJsonFile($"settings.{env.EnvironmentName}.json",optional:false) .AddEnvironmentVariables(); + + Configuration = builder.Build(); } - public IConfigurationRoot Configuration { get; } + - // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(c => { + services.AddSingleton(Configuration); + + services.AddDbContext(c => + { c.UseNpgsql(Configuration["ConnectionString"]); + c.ConfigureWarnings(wb => + { + wb.Throw(RelationalEventId.QueryClientEvaluationWarning); + }); }); // Add framework services. + + services.AddCors(); + services.AddMvcCore() - .AddJsonFormatters(); + .AddJsonFormatters(settings=> + { + settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { + + //Configure logs + + if(env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); + //Seed Data + + CatalogContextSeed.SeedAsync(app) + .Wait(); + + // Use frameworks + app.UseCors(policyBuilder=>policyBuilder.AllowAnyOrigin()); + app.UseMvc(); } } diff --git a/src/Services/Catalog/Catalog.API/project.json b/src/Services/Catalog/Catalog.API/project.json index 563e4d136..020aad4a0 100644 --- a/src/Services/Catalog/Catalog.API/project.json +++ b/src/Services/Catalog/Catalog.API/project.json @@ -1,21 +1,25 @@ { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0", + "version": "1.0.1", "type": "platform" }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.EntityFrameworkCore": "1.0.0", + "Microsoft.AspNetCore.Mvc": "1.0.1", + "Microsoft.AspNetCore.Diagnostics": "1.0.0", + "Microsoft.AspNetCore.Diagnostics.Abstractions": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", + "Microsoft.EntityFrameworkCore": "1.0.1", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Logging": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Npgsql.EntityFrameworkCore.PostgreSQL": "1.0.1" + "Npgsql.EntityFrameworkCore.PostgreSQL": "1.0.2" + }, + "tools": { + }, - "tools": {}, "frameworks": { "netcoreapp1.0": { "imports": [ @@ -39,7 +43,7 @@ "wwwroot", "Views", "Areas/**/Views", - "settings.json", + "settings.Production.json", "web.config", "project.json", "Dockerfile" diff --git a/src/Services/Catalog/Catalog.API/settings.json b/src/Services/Catalog/Catalog.API/settings.development.json similarity index 61% rename from src/Services/Catalog/Catalog.API/settings.json rename to src/Services/Catalog/Catalog.API/settings.development.json index e4f7496f5..3674eb6bc 100644 --- a/src/Services/Catalog/Catalog.API/settings.json +++ b/src/Services/Catalog/Catalog.API/settings.development.json @@ -1,5 +1,5 @@ { - "ConnectionString": "Server=127.0.0.1;Port=5432;Database=postgres;username=postgres", + "ConnectionString": "Server=127.0.0.1;Port=5432;Database=Catalog;username=postgres;password=postgres", "Logging": { "IncludeScopes": false, "LogLevel": { diff --git a/src/Services/Catalog/Catalog.API/settings.production.json b/src/Services/Catalog/Catalog.API/settings.production.json new file mode 100644 index 000000000..a562552b2 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/settings.production.json @@ -0,0 +1,11 @@ +{ + "ConnectionString": "Server=127.0.0.1;Port=5432;Database=CatalogDB;username=postgres;password=postgres", + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} From fbf6adbf6653938eac521dab0b04513715e69819 Mon Sep 17 00:00:00 2001 From: Unai Date: Mon, 31 Oct 2016 16:58:18 +0100 Subject: [PATCH 2/5] remove unused packages --- src/Services/Catalog/Catalog.API/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Catalog/Catalog.API/project.json b/src/Services/Catalog/Catalog.API/project.json index 020aad4a0..50733a295 100644 --- a/src/Services/Catalog/Catalog.API/project.json +++ b/src/Services/Catalog/Catalog.API/project.json @@ -3,7 +3,7 @@ "Microsoft.NETCore.App": { "version": "1.0.1", "type": "platform" - }, + }, "Microsoft.AspNetCore.Mvc": "1.0.1", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics.Abstractions": "1.0.0", From da2282783bdd1513cd3ab59c2d5783b67ca9e049 Mon Sep 17 00:00:00 2001 From: Unai Date: Thu, 3 Nov 2016 12:09:44 +0100 Subject: [PATCH 3/5] Add more web api methods on catalog.api. Implement pagination featue. --- .../Controllers/CatalogController.cs | 63 +++++++++++--- .../Infrastructure/CatalogBrand.cs | 15 ++++ .../Infrastructure/CatalogContext.cs | 86 +++++++++++++++++++ .../Infrastructure/CatalogContextSeed.cs | 75 ++++++++++++++++ .../{Model => Infrastructure}/CatalogItem.cs | 10 ++- .../Catalog.API/Infrastructure/CatalogType.cs | 14 +++ .../Catalog.API/Model/CatalogContext.cs | 46 ---------- .../Catalog.API/Model/CatalogContextSeed.cs | 67 --------------- src/Services/Catalog/Catalog.API/Startup.cs | 2 +- .../ViewModel/PaginatedItemsViewModel.cs | 24 ++++++ 10 files changed, 277 insertions(+), 125 deletions(-) create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs rename src/Services/Catalog/Catalog.API/{Model => Infrastructure}/CatalogItem.cs (53%) create mode 100644 src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs delete mode 100644 src/Services/Catalog/Catalog.API/Model/CatalogContext.cs delete mode 100644 src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs create mode 100644 src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index ccb218a0d..ada0fdfa9 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -3,10 +3,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers { using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; - using Microsoft.eShopOnContainers.Services.Catalog.API.Model; + using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using System; using System.Linq; using System.Threading.Tasks; + using ViewModel; [Route("api/v1/[controller]")] public class CatalogController : ControllerBase @@ -18,29 +19,71 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers _context = context; } - // GET api/v1/[controller]/all + // GET api/v1/[controller]/items/[?pageSize=3&pageIndex=10] [HttpGet] [Route("[action]")] - public async Task All() + public async Task Items(int pageSize = 10, int pageIndex = 0) { - var items = await _context.CatalogItems + var totalItems = await _context.CatalogItems + .LongCountAsync(); + + var itemsOnPage = await _context.CatalogItems + .Skip(pageSize * pageIndex) + .Take(pageSize) + .ToListAsync(); + + var model = new PaginatedItemsViewModel( + pageIndex, pageSize, totalItems, itemsOnPage); + + return Ok(model); + } + + // GET api/v1/[controller]/FindCatalogItemByName/samplename + + [HttpGet] + [Route("[action]/{name:minlength(1)}")] + public async Task Items(string name, int pageSize = 10, int pageIndex = 0) + { + + var totalItems = await _context.CatalogItems + .Where(c => c.Name.StartsWith(name)) + .LongCountAsync(); + + var itemsOnPage = await _context.CatalogItems + .Where(c => c.Name.StartsWith(name)) + .Skip(pageSize * pageIndex) + .Take(pageSize) + .ToListAsync(); + + var model = new PaginatedItemsViewModel( + pageIndex, pageSize, totalItems, itemsOnPage); + + return Ok(model); + } + + // GET api/v1/[controller]/CatalogTypes + + [HttpGet] + [Route("[action]")] + public async Task CatalogTypes() + { + var items = await _context.CatalogTypes .ToListAsync(); return Ok(items); } - // GET api/v1/[controller]/FindByName/samplename + // GET api/v1/[controller]/CatalogBrands [HttpGet] - [Route("FindByName/{name:minlength(1)}")] - public async Task Find(string name) + [Route("[action]")] + public async Task CatalogBrands() { - var items = await _context.CatalogItems - .Where(c => c.Name.StartsWith(name, StringComparison.CurrentCultureIgnoreCase)) + var items = await _context.CatalogBrands .ToListAsync(); - return Ok(); + return Ok(items); } } } diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs new file mode 100644 index 000000000..a8b3cc642 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs @@ -0,0 +1,15 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + + public class CatalogBrand + { + public int Id { get; set; } + + public string Brand { get; set; } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs new file mode 100644 index 000000000..cff069456 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs @@ -0,0 +1,86 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using EntityFrameworkCore.Metadata.Builders; + using Microsoft.EntityFrameworkCore; + using Npgsql.EntityFrameworkCore.PostgreSQL; + + public class CatalogContext : DbContext + { + public CatalogContext(DbContextOptions options) : base(options) + { + } + + public DbSet CatalogItems { get; set; } + + public DbSet CatalogBrands { get; set; } + + public DbSet CatalogTypes { get; set; } + + protected override void OnModelCreating(ModelBuilder builder) + { + builder.HasSequence("idseqcatalog") + .StartsAt(1) + .IncrementsBy(1); + + builder.HasSequence("idseqcatalogbrand") + .StartsAt(1) + .IncrementsBy(1); + + builder.HasSequence("idseqcatalogtype") + .StartsAt(1) + .IncrementsBy(1); + + builder.Entity(ConfigureCatalogItem); + builder.Entity(ConfigureCatalogBrand); + builder.Entity(ConfigureCatalogType); + + builder.HasPostgresExtension("uuid-ossp"); + } + + void ConfigureCatalogItem(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalog"); + + builder.Property(ci => ci.Id) + .HasDefaultValueSql("nextval('idseqcatalog')") + .IsRequired(); + + builder.Property(ci => ci.Name) + .IsRequired(true) + .HasMaxLength(50); + + builder.Property(ci => ci.Price) + .IsRequired(true); + + builder.Property(ci => ci.PictureUri) + .IsRequired(false); + + } + + void ConfigureCatalogBrand(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalogbrand"); + + builder.Property(cb => cb.Id) + .HasDefaultValueSql("nextval('idseqcatalogbrand')") + .IsRequired(); + + builder.Property(cb => cb.Brand) + .IsRequired() + .HasMaxLength(100); + } + + void ConfigureCatalogType(EntityTypeBuilder builder) + { + builder.ForNpgsqlToTable("catalogtype"); + + builder.Property(cb => cb.Id) + .HasDefaultValueSql("nextval('idseqcatalogtype')") + .IsRequired(); + + builder.Property(cb => cb.Type) + .IsRequired() + .HasMaxLength(100); + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs new file mode 100644 index 000000000..76b1d1c53 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs @@ -0,0 +1,75 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using Microsoft.AspNetCore.Builder; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class CatalogContextSeed + { + public static async Task SeedAsync(IApplicationBuilder applicationBuilder) + { + var context = (CatalogContext)applicationBuilder + .ApplicationServices.GetService(typeof(CatalogContext)); + + using (context) + { + context.Database.EnsureCreated(); + + if (!context.CatalogBrands.Any()) + { + context.CatalogBrands.AddRange( + GetPreconfiguredCatalogBrands()); + + await context.SaveChangesAsync(); + } + + if (!context.CatalogTypes.Any()) + { + context.CatalogTypes.AddRange( + GetPreconfiguredCatalogTypes()); + + await context.SaveChangesAsync(); + } + + if (!context.CatalogItems.Any()) + { + context.CatalogItems.AddRange( + GetPreconfiguredItems()); + + await context.SaveChangesAsync(); + } + } + } + + static IEnumerable GetPreconfiguredCatalogBrands() + { + return new List() + { + new CatalogBrand() { Brand="Azure"}, + new CatalogBrand() { Brand = "Visual Studio" } + }; + } + + static IEnumerable GetPreconfiguredCatalogTypes() + { + return new List() + { + new CatalogType() { Type="Mug"}, + new CatalogType() { Type = "T-Shirt" } + }; + } + + static IEnumerable GetPreconfiguredItems() + { + return new List() + { + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + }; + } + } +} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs similarity index 53% rename from src/Services/Catalog/Catalog.API/Model/CatalogItem.cs rename to src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs index b79f7bd1a..0c01486e1 100644 --- a/src/Services/Catalog/Catalog.API/Model/CatalogItem.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs @@ -1,4 +1,4 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure { using System; @@ -14,6 +14,14 @@ public string PictureUri { get; set; } + public int CatalogTypeId { get; set; } + + public CatalogType CatalogType { get; set; } + + public int CatalogBrandId { get; set; } + + public CatalogBrand CatalogBrand { get; set; } + public CatalogItem() { } } } diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs new file mode 100644 index 000000000..5577427fa --- /dev/null +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs @@ -0,0 +1,14 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class CatalogType + { + public int Id { get; set; } + + public string Type { get; set; } + } +} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs deleted file mode 100644 index dc78bce84..000000000 --- a/src/Services/Catalog/Catalog.API/Model/CatalogContext.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model -{ - using EntityFrameworkCore.Metadata.Builders; - using Microsoft.EntityFrameworkCore; - using Npgsql.EntityFrameworkCore.PostgreSQL; - - public class CatalogContext : DbContext - { - public CatalogContext(DbContextOptions options) : base(options) - { - } - - public DbSet CatalogItems { get; set; } - - protected override void OnModelCreating(ModelBuilder builder) - { - builder.HasSequence("idseq") - .StartsAt(1) - .IncrementsBy(1); - - builder.Entity(ConfigureCatalogItem); - - builder.HasPostgresExtension("uuid-ossp"); - } - - void ConfigureCatalogItem(EntityTypeBuilder builder) - { - builder.ForNpgsqlToTable("catalog"); - - builder.Property(ci => ci.Id) - .HasDefaultValueSql("nextval('idseq')") - .IsRequired(); - - builder.Property(ci => ci.Name) - .IsRequired(true) - .HasMaxLength(50); - - builder.Property(ci => ci.Price) - .IsRequired(true); - - builder.Property(ci => ci.PictureUri) - .IsRequired(false); - - } - } -} diff --git a/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs deleted file mode 100644 index a941dc165..000000000 --- a/src/Services/Catalog/Catalog.API/Model/CatalogContextSeed.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model -{ - using Microsoft.AspNetCore.Builder; - using Model; - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - - public class CatalogContextSeed - { - public static async Task SeedAsync(IApplicationBuilder applicationBuilder) - { - var context = (CatalogContext)applicationBuilder - .ApplicationServices.GetService(typeof(CatalogContext)); - - using (context) - { - context.Database.EnsureCreated(); - - if (!context.CatalogItems.Any()) - { - context.CatalogItems.AddRange( - GetPreconfiguredItems()); - - await context.SaveChangesAsync(); - } - } - } - - static IEnumerable GetPreconfiguredItems() - { - return new List() - { - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" } - - }; - } - } -} diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 08a0baafb..9507678a2 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.eShopOnContainers.Services.Catalog.API.Model; +using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs b/src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs new file mode 100644 index 000000000..844f38e2b --- /dev/null +++ b/src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs @@ -0,0 +1,24 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel +{ + using System.Collections.Generic; + + + public class PaginatedItemsViewModel where TEntity : class + { + public int PageIndex { get; private set; } + + public int PageSize { get; private set; } + + public long Count { get; private set; } + + public IEnumerable Data { get; private set; } + + public PaginatedItemsViewModel(int pageIndex, int pageSize, long count, IEnumerable data) + { + this.PageIndex = pageIndex; + this.PageSize = pageSize; + this.Count = count; + this.Data = data; + } + } +} From 728cb0fbfa1cc8b18387c31482c9ffe6e54d7cea Mon Sep 17 00:00:00 2001 From: Unai Date: Thu, 3 Nov 2016 12:11:22 +0100 Subject: [PATCH 4/5] Modify development settings to specify the valid database name --- src/Services/Catalog/Catalog.API/settings.development.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Catalog/Catalog.API/settings.development.json b/src/Services/Catalog/Catalog.API/settings.development.json index 3674eb6bc..a562552b2 100644 --- a/src/Services/Catalog/Catalog.API/settings.development.json +++ b/src/Services/Catalog/Catalog.API/settings.development.json @@ -1,5 +1,5 @@ { - "ConnectionString": "Server=127.0.0.1;Port=5432;Database=Catalog;username=postgres;password=postgres", + "ConnectionString": "Server=127.0.0.1;Port=5432;Database=CatalogDB;username=postgres;password=postgres", "Logging": { "IncludeScopes": false, "LogLevel": { From 725d6586970c1d2bddc83f3e4afcd85c1695f8dd Mon Sep 17 00:00:00 2001 From: Unai Date: Thu, 3 Nov 2016 12:37:46 +0100 Subject: [PATCH 5/5] Add new method in catalog controller to support filter by type and brand --- .../Controllers/CatalogController.cs | 36 +++++++++++++++++-- .../Infrastructure/CatalogContext.cs | 11 +++++- .../Infrastructure/CatalogContextSeed.cs | 2 ++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index ada0fdfa9..e178d9bbc 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -39,10 +39,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers return Ok(model); } - // GET api/v1/[controller]/FindCatalogItemByName/samplename + // GET api/v1/[controller]/items/withname/samplename [HttpGet] - [Route("[action]/{name:minlength(1)}")] + [Route("[action]/withname/{name:minlength(1)}")] public async Task Items(string name, int pageSize = 10, int pageIndex = 0) { @@ -62,6 +62,38 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers return Ok(model); } + // GET api/v1/[controller]/items/type/1/brand/null + + [HttpGet] + [Route("[action]/type/{catalogTypeId}/brand/{catalogBrandId}")] + public async Task Items(int? catalogTypeId, int? catalogBrandId, int pageSize = 10, int pageIndex = 0) + { + var root = (IQueryable)_context.CatalogItems; + + if (catalogTypeId.HasValue) + { + root = root.Where(ci => ci.CatalogTypeId == catalogTypeId); + } + + if (catalogBrandId.HasValue) + { + root = root.Where(ci => ci.CatalogBrandId == catalogBrandId); + } + + var totalItems = await root + .LongCountAsync(); + + var itemsOnPage = await root + .Skip(pageSize * pageIndex) + .Take(pageSize) + .ToListAsync(); + + var model = new PaginatedItemsViewModel( + pageIndex, pageSize, totalItems, itemsOnPage); + + return Ok(model); + } + // GET api/v1/[controller]/CatalogTypes [HttpGet] diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs index cff069456..c2ebe40af 100644 --- a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs @@ -30,9 +30,10 @@ .StartsAt(1) .IncrementsBy(1); - builder.Entity(ConfigureCatalogItem); builder.Entity(ConfigureCatalogBrand); builder.Entity(ConfigureCatalogType); + builder.Entity(ConfigureCatalogItem); + builder.HasPostgresExtension("uuid-ossp"); } @@ -55,6 +56,14 @@ builder.Property(ci => ci.PictureUri) .IsRequired(false); + builder.HasOne(ci => ci.CatalogBrand) + .WithMany() + .HasForeignKey(ci => ci.CatalogBrandId); + + builder.HasOne(ci => ci.CatalogType) + .WithMany() + .HasForeignKey(ci => ci.CatalogTypeId); + } void ConfigureCatalogBrand(EntityTypeBuilder builder) diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs index 76b1d1c53..a5852b331 100644 --- a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs @@ -15,6 +15,8 @@ using (context) { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); if (!context.CatalogBrands.Any())