using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.UI; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.eShopWeb.ApplicationCore.Services; using Microsoft.eShopWeb.Infrastructure.Data; using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Infrastructure.Logging; using Microsoft.eShopWeb.Infrastructure.Services; using Microsoft.eShopWeb.Web.HealthChecks; using Microsoft.eShopWeb.Web.Interfaces; using Microsoft.eShopWeb.Web.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Newtonsoft.Json; using Swashbuckle.AspNetCore.Swagger; using System; using System.Linq; using System.Net.Mime; using System.Text; namespace Microsoft.eShopWeb.Web { public class Startup { private IServiceCollection _services; public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureDevelopmentServices(IServiceCollection services) { // use in-memory database ConfigureInMemoryDatabases(services); // use real database // ConfigureProductionServices(services); } private void ConfigureInMemoryDatabases(IServiceCollection services) { // use in-memory database services.AddDbContext(c => c.UseInMemoryDatabase("Catalog")); // Add Identity DbContext services.AddDbContext(options => options.UseInMemoryDatabase("Identity")); ConfigureServices(services); } public void ConfigureProductionServices(IServiceCollection services) { // use real database // Requires LocalDB which can be installed with SQL Server Express 2016 // https://www.microsoft.com/en-us/download/details.aspx?id=54284 services.AddDbContext(c => c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection"))); // Add Identity DbContext services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"))); ConfigureServices(services); } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { ConfigureCookieSettings(services); CreateIdentityIfNotCreated(services); services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>)); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.Configure(Configuration); services.AddSingleton(new UriComposer(Configuration.Get())); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddTransient(); // Add memory cache services services.AddMemoryCache(); services.AddRouting(options => { // Replace the type and the name used to refer to it with your own // IOutboundParameterTransformer implementation options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer); }); services.AddMvc(options => { options.Conventions.Add(new RouteTokenTransformerConvention( new SlugifyParameterTransformer())); } ) .AddRazorPagesOptions(options => { options.Conventions.AuthorizePage("/Basket/Checkout"); options.AllowAreas = true; }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddHttpContextAccessor(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" }); }); services.AddHealthChecks() .AddCheck("home_page_health_check") .AddCheck("api_health_check"); _services = services; // used to debug registered services } private static void CreateIdentityIfNotCreated(IServiceCollection services) { var sp = services.BuildServiceProvider(); using (var scope = sp.CreateScope()) { var existingUserManager = scope.ServiceProvider .GetService>(); if(existingUserManager == null) { services.AddIdentity() .AddDefaultUI(UIFramework.Bootstrap4) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); } } } private static void ConfigureCookieSettings(IServiceCollection services) { services.Configure(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = true; options.ExpireTimeSpan = TimeSpan.FromHours(1); options.LoginPath = "/Account/Login"; options.LogoutPath = "/Account/Signout"; options.Cookie = new CookieBuilder { IsEssential = true // required for auth to work without explicit user consent; adjust to suit your privacy policy }; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, LinkGenerator linkGenerator) { //app.UseDeveloperExceptionPage(); app.UseHealthChecks("/health", new HealthCheckOptions { ResponseWriter = async (context, report) => { var result = JsonConvert.SerializeObject( new { status = report.Status.ToString(), errors = report.Entries.Select(e => new { key = e.Key, value = Enum.GetName(typeof(HealthStatus), e.Value.Status) }) }); context.Response.ContentType = MediaTypeNames.Application.Json; await context.Response.WriteAsync(result); } }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); ListAllRegisteredServices(app, linkGenerator); app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); app.UseAuthentication(); // Enable middleware to serve generated Swagger as a JSON endpoint. app.UseSwagger(); // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), // specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); app.UseMvc(routes => { routes.MapRoute( name: "identity", template: "Identity/{controller=Account}/{action=Register}/{id?}"); routes.MapRoute( name: "default", template: "{controller:slugify=Home}/{action:slugify=Index}/{id?}"); }); } private void ListAllRegisteredServices(IApplicationBuilder app, LinkGenerator linkGenerator) { var homePageLink = linkGenerator.GetPathByAction("Index", "Catalog"); var loginLink = linkGenerator.GetPathByAction("SignIn", "Account"); app.Map("/allservices", builder => builder.Run(async context => { var sb = new StringBuilder(); sb.Append("Return to site | "); sb.Append("Login to site"); sb.Append("

All Services

"); sb.Append(""); sb.Append(""); sb.Append(""); foreach (var svc in _services) { sb.Append(""); sb.Append($""); sb.Append($""); sb.Append($""); sb.Append(""); } sb.Append("
TypeLifetimeInstance
{svc.ServiceType.FullName}{svc.Lifetime}{svc.ImplementationType?.FullName}
"); await context.Response.WriteAsync(sb.ToString()); })); } } }