Browse Source

Merge branch 'Dev' into WebMvc

pull/49/merge
Carlos Cañizares Estévez 8 years ago
parent
commit
45bc1f8929
15 changed files with 411 additions and 105 deletions
  1. +88
    -40
      src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
  2. +1
    -1
      src/Services/Catalog/Catalog.API/Dockerfile
  3. +15
    -0
      src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs
  4. +95
    -0
      src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs
  5. +77
    -0
      src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs
  6. +27
    -0
      src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs
  7. +14
    -0
      src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs
  8. +0
    -23
      src/Services/Catalog/Catalog.API/Model/CatalogContext.cs
  9. +0
    -20
      src/Services/Catalog/Catalog.API/Model/CatalogItem.cs
  10. +1
    -0
      src/Services/Catalog/Catalog.API/Program.cs
  11. +45
    -12
      src/Services/Catalog/Catalog.API/Startup.cs
  12. +24
    -0
      src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs
  13. +12
    -8
      src/Services/Catalog/Catalog.API/project.json
  14. +1
    -1
      src/Services/Catalog/Catalog.API/settings.development.json
  15. +11
    -0
      src/Services/Catalog/Catalog.API/settings.production.json

+ 88
- 40
src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs View File

@ -1,73 +1,121 @@
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.Infrastructure;
using System;
using System.Linq;
using System.Threading.Tasks;
using ViewModel;
[Route("api/v1/[controller]")]
public class CatalogController : ControllerBase
{
private CatalogContext _context;
private readonly CatalogContext _context;
public CatalogController(CatalogContext context)
{
_context = context;
}
// GET api/values
// GET api/v1/[controller]/items/[?pageSize=3&pageIndex=10]
[HttpGet]
public IEnumerable<CatalogItem> Get()
[Route("[action]")]
public async Task<IActionResult> Items(int pageSize = 10, int pageIndex = 0)
{
return _context.CatalogItems.ToList();
var totalItems = await _context.CatalogItems
.LongCountAsync();
var itemsOnPage = await _context.CatalogItems
.Skip(pageSize * pageIndex)
.Take(pageSize)
.ToListAsync();
var model = new PaginatedItemsViewModel<CatalogItem>(
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
}
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(Guid id)
// GET api/v1/[controller]/items/withname/samplename
[HttpGet]
[Route("[action]/withname/{name:minlength(1)}")]
public async Task<IActionResult> Items(string name, int pageSize = 10, int pageIndex = 0)
{
var item = _context.CatalogItems.FirstOrDefault(x=> x.Id == id);
if(item == null)
{
return NotFound();
}
var totalItems = await _context.CatalogItems
.Where(c => c.Name.StartsWith(name))
.LongCountAsync();
return new OkObjectResult(item);
var itemsOnPage = await _context.CatalogItems
.Where(c => c.Name.StartsWith(name))
.Skip(pageSize * pageIndex)
.Take(pageSize)
.ToListAsync();
var model = new PaginatedItemsViewModel<CatalogItem>(
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
}
// POST api/values
[HttpPost]
public IActionResult Post([FromBody]CatalogItem item)
// GET api/v1/[controller]/items/type/1/brand/null
[HttpGet]
[Route("[action]/type/{catalogTypeId}/brand/{catalogBrandId}")]
public async Task<IActionResult> Items(int? catalogTypeId, int? catalogBrandId, int pageSize = 10, int pageIndex = 0)
{
try
var root = (IQueryable<CatalogItem>)_context.CatalogItems;
if (catalogTypeId.HasValue)
{
_context.CatalogItems.Add(item);
_context.SaveChanges();
return Ok();
root = root.Where(ci => ci.CatalogTypeId == catalogTypeId);
}
catch
if (catalogBrandId.HasValue)
{
return StatusCode(500, "Unable to add new catalog item");
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<CatalogItem>(
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
}
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody]CatalogItem item)
// GET api/v1/[controller]/CatalogTypes
[HttpGet]
[Route("[action]")]
public async Task<IActionResult> CatalogTypes()
{
_context.CatalogItems.Update(item);
_context.SaveChanges();
return Ok();
var items = await _context.CatalogTypes
.ToListAsync();
return Ok(items);
}
// DELETE api/values/5
[HttpDelete("{id}")]
public IActionResult Delete(Guid id)
// GET api/v1/[controller]/CatalogBrands
[HttpGet]
[Route("[action]")]
public async Task<IActionResult> CatalogBrands()
{
return Ok();
var items = await _context.CatalogBrands
.ToListAsync();
return Ok(items);
}
}
}

+ 1
- 1
src/Services/Catalog/Catalog.API/Dockerfile View File

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore
FROM microsoft/aspnetcore:latest
WORKDIR /app
EXPOSE 80
ADD . /app

+ 15
- 0
src/Services/Catalog/Catalog.API/Infrastructure/CatalogBrand.cs View File

@ -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; }
}
}

+ 95
- 0
src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs View File

@ -0,0 +1,95 @@
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<CatalogItem> CatalogItems { get; set; }
public DbSet<CatalogBrand> CatalogBrands { get; set; }
public DbSet<CatalogType> 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<CatalogBrand>(ConfigureCatalogBrand);
builder.Entity<CatalogType>(ConfigureCatalogType);
builder.Entity<CatalogItem>(ConfigureCatalogItem);
builder.HasPostgresExtension("uuid-ossp");
}
void ConfigureCatalogItem(EntityTypeBuilder<CatalogItem> 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);
builder.HasOne(ci => ci.CatalogBrand)
.WithMany()
.HasForeignKey(ci => ci.CatalogBrandId);
builder.HasOne(ci => ci.CatalogType)
.WithMany()
.HasForeignKey(ci => ci.CatalogTypeId);
}
void ConfigureCatalogBrand(EntityTypeBuilder<CatalogBrand> builder)
{
builder.ForNpgsqlToTable("catalogbrand");
builder.Property(cb => cb.Id)
.HasDefaultValueSql("nextval('idseqcatalogbrand')")
.IsRequired();
builder.Property(cb => cb.Brand)
.IsRequired()
.HasMaxLength(100);
}
void ConfigureCatalogType(EntityTypeBuilder<CatalogType> builder)
{
builder.ForNpgsqlToTable("catalogtype");
builder.Property(cb => cb.Id)
.HasDefaultValueSql("nextval('idseqcatalogtype')")
.IsRequired();
builder.Property(cb => cb.Type)
.IsRequired()
.HasMaxLength(100);
}
}
}

+ 77
- 0
src/Services/Catalog/Catalog.API/Infrastructure/CatalogContextSeed.cs View File

@ -0,0 +1,77 @@
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.EnsureDeleted();
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<CatalogBrand> GetPreconfiguredCatalogBrands()
{
return new List<CatalogBrand>()
{
new CatalogBrand() { Brand="Azure"},
new CatalogBrand() { Brand = "Visual Studio" }
};
}
static IEnumerable<CatalogType> GetPreconfiguredCatalogTypes()
{
return new List<CatalogType>()
{
new CatalogType() { Type="Mug"},
new CatalogType() { Type = "T-Shirt" }
};
}
static IEnumerable<CatalogItem> GetPreconfiguredItems()
{
return new List<CatalogItem>()
{
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" },
};
}
}
}

+ 27
- 0
src/Services/Catalog/Catalog.API/Infrastructure/CatalogItem.cs View File

@ -0,0 +1,27 @@
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure
{
using System;
public class CatalogItem
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
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() { }
}
}

+ 14
- 0
src/Services/Catalog/Catalog.API/Infrastructure/CatalogType.cs View File

@ -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; }
}
}

+ 0
- 23
src/Services/Catalog/Catalog.API/Model/CatalogContext.cs View File

@ -1,23 +0,0 @@
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
{
public class CatalogContext : DbContext
{
public CatalogContext(DbContextOptions options): base(options)
{
}
public DbSet<CatalogItem> CatalogItems { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasPostgresExtension("uuid-ossp");
}
}
}

+ 0
- 20
src/Services/Catalog/Catalog.API/Model/CatalogItem.cs View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Model
{
public class CatalogItem
{
public CatalogItem()
{
}
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; }
}
}

+ 1
- 0
src/Services/Catalog/Catalog.API/Program.cs View File

@ -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<Startup>()
.Build();


+ 45
- 12
src/Services/Catalog/Catalog.API/Startup.cs View File

@ -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.Infrastructure;
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<CatalogContext>(c => {
services.AddSingleton<IConfiguration>(Configuration);
services.AddDbContext<CatalogContext>(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();
}
}


+ 24
- 0
src/Services/Catalog/Catalog.API/ViewModel/PaginatedItemsViewModel.cs View File

@ -0,0 +1,24 @@
namespace Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel
{
using System.Collections.Generic;
public class PaginatedItemsViewModel<TEntity> where TEntity : class
{
public int PageIndex { get; private set; }
public int PageSize { get; private set; }
public long Count { get; private set; }
public IEnumerable<TEntity> Data { get; private set; }
public PaginatedItemsViewModel(int pageIndex, int pageSize, long count, IEnumerable<TEntity> data)
{
this.PageIndex = pageIndex;
this.PageSize = pageSize;
this.Count = count;
this.Data = data;
}
}
}

+ 12
- 8
src/Services/Catalog/Catalog.API/project.json View File

@ -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"


src/Services/Catalog/Catalog.API/settings.json → src/Services/Catalog/Catalog.API/settings.development.json View File

@ -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=CatalogDB;username=postgres;password=postgres",
"Logging": {
"IncludeScopes": false,
"LogLevel": {

+ 11
- 0
src/Services/Catalog/Catalog.API/settings.production.json View File

@ -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"
}
}
}

Loading…
Cancel
Save