diff --git a/src/Web/WebMonolithic/docker-compose.override.yml b/src/Web/WebMonolithic/docker-compose.override.yml index 22b88ccca..8822a5f63 100644 --- a/src/Web/WebMonolithic/docker-compose.override.yml +++ b/src/Web/WebMonolithic/docker-compose.override.yml @@ -4,6 +4,7 @@ services: eshopweb: environment: - ASPNETCORE_ENVIRONMENT=Development + - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word ports: - "5106:5106" diff --git a/src/Web/WebMonolithic/eShopWeb/Dockerfile b/src/Web/WebMonolithic/eShopWeb/Dockerfile index c27a6da40..010cee1c3 100644 --- a/src/Web/WebMonolithic/eShopWeb/Dockerfile +++ b/src/Web/WebMonolithic/eShopWeb/Dockerfile @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore:1.0 +FROM microsoft/aspnetcore:1.1 ARG source WORKDIR /app EXPOSE 80 diff --git a/src/Web/WebMonolithic/eShopWeb/Infrastructure/CatalogContext.cs b/src/Web/WebMonolithic/eShopWeb/Infrastructure/CatalogContext.cs new file mode 100644 index 000000000..cb6e9c1cd --- /dev/null +++ b/src/Web/WebMonolithic/eShopWeb/Infrastructure/CatalogContext.cs @@ -0,0 +1,79 @@ +namespace eShopWeb.Infrastructure +{ + using eShopWeb.Models; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + + 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.Entity(ConfigureCatalogBrand); + builder.Entity(ConfigureCatalogType); + builder.Entity(ConfigureCatalogItem); + } + + void ConfigureCatalogItem(EntityTypeBuilder builder) + { + builder.ToTable("Catalog"); + + builder.Property(ci => ci.Id) + .ForSqlServerUseSequenceHiLo("catalog_hilo") + .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 builder) + { + builder.ToTable("CatalogBrand"); + + builder.HasKey(ci => ci.Id); + + builder.Property(ci => ci.Id) + .ForSqlServerUseSequenceHiLo("catalog_brand_hilo") + .IsRequired(); + + builder.Property(cb => cb.Brand) + .IsRequired() + .HasMaxLength(100); + } + + void ConfigureCatalogType(EntityTypeBuilder builder) + { + builder.ToTable("CatalogType"); + + builder.HasKey(ci => ci.Id); + + builder.Property(ci => ci.Id) + .ForSqlServerUseSequenceHiLo("catalog_type_hilo") + .IsRequired(); + + builder.Property(cb => cb.Type) + .IsRequired() + .HasMaxLength(100); + } + } +} diff --git a/src/Web/WebMonolithic/eShopWeb/Infrastructure/CatalogContextSeed.cs b/src/Web/WebMonolithic/eShopWeb/Infrastructure/CatalogContextSeed.cs new file mode 100644 index 000000000..64dd74d5a --- /dev/null +++ b/src/Web/WebMonolithic/eShopWeb/Infrastructure/CatalogContextSeed.cs @@ -0,0 +1,103 @@ +namespace eShopWeb.Infrastructure +{ + using eShopWeb.Models; + using Microsoft.AspNetCore.Builder; + using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Logging; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class CatalogContextSeed + { + public static async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory, int? retry = 0) + { + int retryForAvaiability = retry.Value; + try + { + var context = (CatalogContext)applicationBuilder + .ApplicationServices.GetService(typeof(CatalogContext)); + + //context.Database.Migrate(); + 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(); + } + } + catch (Exception ex) + { + if (retryForAvaiability < 10) + { + retryForAvaiability++; + var log = loggerFactory.CreateLogger("catalog seed"); + log.LogError(ex.Message); + await SeedAsync(applicationBuilder, loggerFactory, retryForAvaiability); + } + } + } + + static IEnumerable GetPreconfiguredCatalogBrands() + { + return new List() + { + new CatalogBrand() { Brand = "Azure"}, + new CatalogBrand() { Brand = ".NET" }, + new CatalogBrand() { Brand = "Visual Studio" }, + new CatalogBrand() { Brand = "SQL Server" }, + new CatalogBrand() { Brand = "Other" } + }; + } + + static IEnumerable GetPreconfiguredCatalogTypes() + { + return new List() + { + new CatalogType() { Type = "Mug"}, + new CatalogType() { Type = "T-Shirt" }, + new CatalogType() { Type = "Sheet" }, + new CatalogType() { Type = "USB Memory Stick" } + }; + } + + static IEnumerable GetPreconfiguredItems() + { + return new List() + { + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/1" }, + new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/2" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/3" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Foundation Sweatshirt", Name = ".NET Foundation Sweatshirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/4" }, + new CatalogItem() { CatalogTypeId=3,CatalogBrandId=5, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/5" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Blue Sweatshirt", Name = ".NET Blue Sweatshirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/6" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/7" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Kudu Purple Sweatshirt", Name = "Kudu Purple Sweatshirt", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/8" }, + new CatalogItem() { CatalogTypeId=1,CatalogBrandId=5, Description = "Cup White Mug", Name = "Cup White Mug", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/9" }, + new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/10" }, + new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = "Cup Sheet", Name = "Cup Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/11" }, + new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White TShirt", Name = "Prism White TShirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/12" } + }; + } + } +} diff --git a/src/Web/WebMonolithic/eShopWeb/Models/CatalogBrand.cs b/src/Web/WebMonolithic/eShopWeb/Models/CatalogBrand.cs new file mode 100644 index 000000000..9488eec5a --- /dev/null +++ b/src/Web/WebMonolithic/eShopWeb/Models/CatalogBrand.cs @@ -0,0 +1,15 @@ +namespace eShopWeb.Models +{ + 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/Web/WebMonolithic/eShopWeb/Models/CatalogItem.cs b/src/Web/WebMonolithic/eShopWeb/Models/CatalogItem.cs index 6341a4b6a..6970f1cd2 100644 --- a/src/Web/WebMonolithic/eShopWeb/Models/CatalogItem.cs +++ b/src/Web/WebMonolithic/eShopWeb/Models/CatalogItem.cs @@ -4,15 +4,24 @@ namespace eShopWeb.Models { public class CatalogItem { - public string 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 CatalogBrandId { get; set; } - public string CatalogBrand { get; set; } - public int CatalogTypeId { get; set; } - public string CatalogType { get; set; } + 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() { } } } \ No newline at end of file diff --git a/src/Web/WebMonolithic/eShopWeb/Models/CatalogType.cs b/src/Web/WebMonolithic/eShopWeb/Models/CatalogType.cs new file mode 100644 index 000000000..427a5d21e --- /dev/null +++ b/src/Web/WebMonolithic/eShopWeb/Models/CatalogType.cs @@ -0,0 +1,14 @@ +namespace eShopWeb.Models +{ + 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/Web/WebMonolithic/eShopWeb/Services/CatalogService.cs b/src/Web/WebMonolithic/eShopWeb/Services/CatalogService.cs new file mode 100644 index 000000000..dc1dda2f1 --- /dev/null +++ b/src/Web/WebMonolithic/eShopWeb/Services/CatalogService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using eShopWeb.Models; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace eShopWeb.Services +{ + public class CatalogService : ICatalogService + { + public IEnumerable GetBrands() + { + throw new NotImplementedException(); + } + + public IList GetCatalogItems(int page, int itemsPage, int? brandFilterApplied, int? typesFilterApplied) + { + throw new NotImplementedException(); + } + + public IEnumerable GetTypes() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Web/WebMonolithic/eShopWeb/Services/ICatalogService.cs b/src/Web/WebMonolithic/eShopWeb/Services/ICatalogService.cs new file mode 100644 index 000000000..85598e34f --- /dev/null +++ b/src/Web/WebMonolithic/eShopWeb/Services/ICatalogService.cs @@ -0,0 +1,16 @@ +using eShopWeb.Models; +using Microsoft.AspNetCore.Mvc.Rendering; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace eShopWeb.Services +{ + public interface ICatalogService + { + IList GetCatalogItems(int page, int itemsPage, int? brandFilterApplied, int? typesFilterApplied); + IEnumerable GetBrands(); + IEnumerable GetTypes(); + } +} diff --git a/src/Web/WebMonolithic/eShopWeb/Startup.cs b/src/Web/WebMonolithic/eShopWeb/Startup.cs index 87f9136ef..5b62ea3a4 100644 --- a/src/Web/WebMonolithic/eShopWeb/Startup.cs +++ b/src/Web/WebMonolithic/eShopWeb/Startup.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using eShopWeb.Infrastructure; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -27,7 +26,24 @@ namespace eShopWeb // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - // Add framework services. + services.AddDbContext(c => + { + try + { + var text = Configuration["ConnectionString"]; + c.UseSqlServer(Configuration["ConnectionString"]); + c.ConfigureWarnings(wb => + { + //By default, in this application, we don't want to have client evaluations + wb.Log(RelationalEventId.QueryClientEvaluationWarning); + }); + } + catch (System.Exception ex ) + { + var message = ex.Message; + } + }); + services.AddMvc(); } @@ -55,6 +71,10 @@ namespace eShopWeb name: "default", template: "{controller=Catalog}/{action=Index}/{id?}"); }); + + //Seed Data + CatalogContextSeed.SeedAsync(app, loggerFactory) + .Wait(); } } } diff --git a/src/Web/WebMonolithic/eShopWeb/appsettings.json b/src/Web/WebMonolithic/eShopWeb/appsettings.json index 5fff67bac..f0ecd70d3 100644 --- a/src/Web/WebMonolithic/eShopWeb/appsettings.json +++ b/src/Web/WebMonolithic/eShopWeb/appsettings.json @@ -1,4 +1,5 @@ { + "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word", "Logging": { "IncludeScopes": false, "LogLevel": { diff --git a/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj b/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj index e66d0eb05..8880c7561 100644 --- a/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj +++ b/src/Web/WebMonolithic/eShopWeb/eShopWeb.csproj @@ -1,7 +1,7 @@  - netcoreapp1.0 + netcoreapp1.1 @@ -9,45 +9,17 @@ ..\docker-compose.dcproj - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + @@ -55,7 +27,8 @@ - + +