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 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 public class CatalogController : ControllerBase
{ {
private CatalogContext _context;
private readonly CatalogContext _context;
public CatalogController(CatalogContext context) public CatalogController(CatalogContext context)
{ {
_context = context; _context = context;
} }
// GET api/values
// GET api/v1/[controller]/items/[?pageSize=3&pageIndex=10]
[HttpGet] [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 WORKDIR /app
EXPOSE 80 EXPOSE 80
ADD . /app 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() var host = new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls(Environment.GetEnvironmentVariable("ASPNETCORE_URLS") ?? String.Empty)
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>() .UseStartup<Startup>()
.Build(); .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.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.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; 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 namespace Microsoft.eShopOnContainers.Services.Catalog.API
{ {
public class Startup public class Startup
{ {
public IConfigurationRoot Configuration { get; }
public Startup(IHostingEnvironment env) public Startup(IHostingEnvironment env)
{ {
var builder = new ConfigurationBuilder() var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath) .SetBasePath(env.ContentRootPath)
.AddJsonFile("settings.json")
.AddJsonFile($"settings.{env.EnvironmentName}.json",optional:false)
.AddEnvironmentVariables(); .AddEnvironmentVariables();
Configuration = builder.Build(); 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) public void ConfigureServices(IServiceCollection services)
{ {
services.AddDbContext<CatalogContext>(c => {
services.AddSingleton<IConfiguration>(Configuration);
services.AddDbContext<CatalogContext>(c =>
{
c.UseNpgsql(Configuration["ConnectionString"]); c.UseNpgsql(Configuration["ConnectionString"]);
c.ConfigureWarnings(wb =>
{
wb.Throw(RelationalEventId.QueryClientEvaluationWarning);
});
}); });
// Add framework services. // Add framework services.
services.AddCors();
services.AddMvcCore() 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. // 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) public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {
//Configure logs
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug(); loggerFactory.AddDebug();
//Seed Data
CatalogContextSeed.SeedAsync(app)
.Wait();
// Use frameworks
app.UseCors(policyBuilder=>policyBuilder.AllowAnyOrigin());
app.UseMvc(); 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": { "dependencies": {
"Microsoft.NETCore.App": { "Microsoft.NETCore.App": {
"version": "1.0.0",
"version": "1.0.1",
"type": "platform" "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.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0", "Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "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": { "frameworks": {
"netcoreapp1.0": { "netcoreapp1.0": {
"imports": [ "imports": [
@ -39,7 +43,7 @@
"wwwroot", "wwwroot",
"Views", "Views",
"Areas/**/Views", "Areas/**/Views",
"settings.json",
"settings.Production.json",
"web.config", "web.config",
"project.json", "project.json",
"Dockerfile" "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": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "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