Browse Source
* Converting to net6 startup and integration test formats * Update to minimal api and using pagetitle * Adjust functional test fixtures Update ApiEndpoints package version * Finish migration to minimal api startupmain
committed by
GitHub
34 changed files with 485 additions and 714 deletions
@ -1,50 +1,186 @@ |
|||||
using System; |
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using BlazorShared; |
||||
|
using BlazorShared.Models; |
||||
|
using MediatR; |
||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
using Microsoft.AspNetCore.Hosting; |
using Microsoft.AspNetCore.Hosting; |
||||
using Microsoft.AspNetCore.Identity; |
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.eShopWeb; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Constants; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Services; |
||||
using Microsoft.eShopWeb.Infrastructure.Data; |
using Microsoft.eShopWeb.Infrastructure.Data; |
||||
using Microsoft.eShopWeb.Infrastructure.Identity; |
using Microsoft.eShopWeb.Infrastructure.Identity; |
||||
|
using Microsoft.eShopWeb.Infrastructure.Logging; |
||||
|
using Microsoft.eShopWeb.PublicApi; |
||||
|
using Microsoft.eShopWeb.PublicApi.Middleware; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Hosting; |
using Microsoft.Extensions.Hosting; |
||||
using Microsoft.Extensions.Logging; |
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
using Microsoft.OpenApi.Models; |
||||
|
|
||||
namespace Microsoft.eShopWeb.PublicApi; |
var builder = WebApplication.CreateBuilder(args); |
||||
|
|
||||
public class Program |
builder.Logging.AddConsole(); |
||||
|
|
||||
|
// 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
|
||||
|
builder.Services.AddDbContext<CatalogContext>(c => |
||||
|
c.UseSqlServer(builder.Configuration.GetConnectionString("CatalogConnection"))); |
||||
|
|
||||
|
// Add Identity DbContext
|
||||
|
builder.Services.AddDbContext<AppIdentityDbContext>(options => |
||||
|
options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityConnection"))); |
||||
|
|
||||
|
builder.Services.AddIdentity<ApplicationUser, IdentityRole>() |
||||
|
.AddEntityFrameworkStores<AppIdentityDbContext>() |
||||
|
.AddDefaultTokenProviders(); |
||||
|
|
||||
|
builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); |
||||
|
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>)); |
||||
|
builder.Services.Configure<CatalogSettings>(builder.Configuration); |
||||
|
builder.Services.AddSingleton<IUriComposer>(new UriComposer(builder.Configuration.Get<CatalogSettings>())); |
||||
|
builder.Services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); |
||||
|
builder.Services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>(); |
||||
|
|
||||
|
var configSection = builder.Configuration.GetRequiredSection(BaseUrlConfiguration.CONFIG_NAME); |
||||
|
builder.Services.Configure<BaseUrlConfiguration>(configSection); |
||||
|
var baseUrlConfig = configSection.Get<BaseUrlConfiguration>(); |
||||
|
|
||||
|
builder.Services.AddMemoryCache(); |
||||
|
|
||||
|
var key = Encoding.ASCII.GetBytes(AuthorizationConstants.JWT_SECRET_KEY); |
||||
|
builder.Services.AddAuthentication(config => |
||||
{ |
{ |
||||
public static async Task Main(string[] args) |
config.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; |
||||
|
}) |
||||
|
.AddJwtBearer(config => |
||||
{ |
{ |
||||
var host = CreateHostBuilder(args) |
config.RequireHttpsMetadata = false; |
||||
.Build(); |
config.SaveToken = true; |
||||
|
config.TokenValidationParameters = new TokenValidationParameters |
||||
|
{ |
||||
|
ValidateIssuerSigningKey = true, |
||||
|
IssuerSigningKey = new SymmetricSecurityKey(key), |
||||
|
ValidateIssuer = false, |
||||
|
ValidateAudience = false |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
using (var scope = host.Services.CreateScope()) |
const string CORS_POLICY = "CorsPolicy"; |
||||
|
builder.Services.AddCors(options => |
||||
{ |
{ |
||||
var services = scope.ServiceProvider; |
options.AddPolicy(name: CORS_POLICY, |
||||
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); |
builder => |
||||
try |
|
||||
{ |
{ |
||||
var catalogContext = services.GetRequiredService<CatalogContext>(); |
builder.WithOrigins(baseUrlConfig.WebBase.Replace("host.docker.internal", "localhost").TrimEnd('/')); |
||||
await CatalogContextSeed.SeedAsync(catalogContext, loggerFactory); |
builder.AllowAnyMethod(); |
||||
|
builder.AllowAnyHeader(); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>(); |
builder.Services.AddControllers(); |
||||
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>(); |
|
||||
await AppIdentityDbContextSeed.SeedAsync(userManager, roleManager); |
builder.Services.AddMediatR(typeof(CatalogItem).Assembly); |
||||
} |
builder.Services.AddAutoMapper(typeof(MappingProfile).Assembly); |
||||
catch (Exception ex) |
|
||||
|
builder.Services.AddSwaggerGen(c => |
||||
{ |
{ |
||||
var logger = loggerFactory.CreateLogger<Program>(); |
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); |
||||
logger.LogError(ex, "An error occurred seeding the DB."); |
c.EnableAnnotations(); |
||||
} |
c.SchemaFilter<CustomSchemaFilters>(); |
||||
|
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
||||
|
{ |
||||
|
Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n
|
||||
|
Enter 'Bearer' [space] and then your token in the text input below. |
||||
|
\r\n\r\nExample: 'Bearer 12345abcdef'",
|
||||
|
Name = "Authorization", |
||||
|
In = ParameterLocation.Header, |
||||
|
Type = SecuritySchemeType.ApiKey, |
||||
|
Scheme = "Bearer" |
||||
|
}); |
||||
|
|
||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement() |
||||
|
{ |
||||
|
{ |
||||
|
new OpenApiSecurityScheme |
||||
|
{ |
||||
|
Reference = new OpenApiReference |
||||
|
{ |
||||
|
Type = ReferenceType.SecurityScheme, |
||||
|
Id = "Bearer" |
||||
|
}, |
||||
|
Scheme = "oauth2", |
||||
|
Name = "Bearer", |
||||
|
In = ParameterLocation.Header, |
||||
|
|
||||
|
}, |
||||
|
new List<string>() |
||||
} |
} |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
var app = builder.Build(); |
||||
|
|
||||
|
app.Logger.LogInformation("PublicApi App created..."); |
||||
|
|
||||
host.Run(); |
if (app.Environment.IsDevelopment()) |
||||
|
{ |
||||
|
app.UseDeveloperExceptionPage(); |
||||
} |
} |
||||
|
|
||||
|
app.UseMiddleware<ExceptionMiddleware>(); |
||||
|
|
||||
|
app.UseHttpsRedirection(); |
||||
|
|
||||
|
app.UseRouting(); |
||||
|
|
||||
|
app.UseCors(CORS_POLICY); |
||||
|
|
||||
|
app.UseAuthorization(); |
||||
|
|
||||
|
// 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"); |
||||
|
}); |
||||
|
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) => |
app.UseEndpoints(endpoints => |
||||
Host.CreateDefaultBuilder(args) |
|
||||
.ConfigureWebHostDefaults(webBuilder => |
|
||||
{ |
{ |
||||
webBuilder.UseStartup<Startup>(); |
endpoints.MapControllers(); |
||||
}); |
}); |
||||
|
|
||||
|
app.Logger.LogInformation("Seeding Database..."); |
||||
|
|
||||
|
using (var scope = app.Services.CreateScope()) |
||||
|
{ |
||||
|
var scopedProvider = scope.ServiceProvider; |
||||
|
try |
||||
|
{ |
||||
|
var catalogContext = scopedProvider.GetRequiredService<CatalogContext>(); |
||||
|
await CatalogContextSeed.SeedAsync(catalogContext, app.Logger); |
||||
|
|
||||
|
var userManager = scopedProvider.GetRequiredService<UserManager<ApplicationUser>>(); |
||||
|
var roleManager = scopedProvider.GetRequiredService<RoleManager<IdentityRole>>(); |
||||
|
await AppIdentityDbContextSeed.SeedAsync(userManager, roleManager); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
app.Logger.LogError(ex, "An error occurred seeding the DB."); |
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
app.Logger.LogInformation("LAUNCHING PublicApi"); |
||||
|
app.Run(); |
||||
|
|||||
@ -1,208 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Text; |
|
||||
using AutoMapper; |
|
||||
using BlazorShared; |
|
||||
using MediatR; |
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|
||||
using Microsoft.AspNetCore.Builder; |
|
||||
using Microsoft.AspNetCore.Hosting; |
|
||||
using Microsoft.AspNetCore.Identity; |
|
||||
using Microsoft.EntityFrameworkCore; |
|
||||
using Microsoft.eShopWeb.ApplicationCore.Constants; |
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|
||||
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.PublicApi.MiddleWares; |
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Hosting; |
|
||||
using Microsoft.IdentityModel.Tokens; |
|
||||
using Microsoft.OpenApi.Models; |
|
||||
|
|
||||
namespace Microsoft.eShopWeb.PublicApi; |
|
||||
|
|
||||
public class Startup |
|
||||
{ |
|
||||
private const string CORS_POLICY = "CorsPolicy"; |
|
||||
|
|
||||
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);
|
|
||||
} |
|
||||
|
|
||||
public void ConfigureDockerServices(IServiceCollection services) |
|
||||
{ |
|
||||
ConfigureDevelopmentServices(services); |
|
||||
} |
|
||||
|
|
||||
private void ConfigureInMemoryDatabases(IServiceCollection services) |
|
||||
{ |
|
||||
services.AddDbContext<CatalogContext>(c => |
|
||||
c.UseInMemoryDatabase("Catalog")); |
|
||||
|
|
||||
services.AddDbContext<AppIdentityDbContext>(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<CatalogContext>(c => |
|
||||
c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection"))); |
|
||||
|
|
||||
// Add Identity DbContext
|
|
||||
services.AddDbContext<AppIdentityDbContext>(options => |
|
||||
options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"))); |
|
||||
|
|
||||
ConfigureServices(services); |
|
||||
} |
|
||||
|
|
||||
public void ConfigureTestingServices(IServiceCollection services) |
|
||||
{ |
|
||||
ConfigureInMemoryDatabases(services); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
|
||||
public void ConfigureServices(IServiceCollection services) |
|
||||
{ |
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>() |
|
||||
.AddEntityFrameworkStores<AppIdentityDbContext>() |
|
||||
.AddDefaultTokenProviders(); |
|
||||
|
|
||||
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); |
|
||||
services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>)); |
|
||||
services.Configure<CatalogSettings>(Configuration); |
|
||||
services.AddSingleton<IUriComposer>(new UriComposer(Configuration.Get<CatalogSettings>())); |
|
||||
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); |
|
||||
services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>(); |
|
||||
|
|
||||
var configSection = Configuration.GetRequiredSection(BaseUrlConfiguration.CONFIG_NAME); |
|
||||
services.Configure<BaseUrlConfiguration>(configSection); |
|
||||
var baseUrlConfig = configSection.Get<BaseUrlConfiguration>(); |
|
||||
|
|
||||
services.AddMemoryCache(); |
|
||||
|
|
||||
var key = Encoding.ASCII.GetBytes(AuthorizationConstants.JWT_SECRET_KEY); |
|
||||
services.AddAuthentication(config => |
|
||||
{ |
|
||||
config.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; |
|
||||
}) |
|
||||
.AddJwtBearer(config => |
|
||||
{ |
|
||||
config.RequireHttpsMetadata = false; |
|
||||
config.SaveToken = true; |
|
||||
config.TokenValidationParameters = new TokenValidationParameters |
|
||||
{ |
|
||||
ValidateIssuerSigningKey = true, |
|
||||
IssuerSigningKey = new SymmetricSecurityKey(key), |
|
||||
ValidateIssuer = false, |
|
||||
ValidateAudience = false |
|
||||
}; |
|
||||
}); |
|
||||
|
|
||||
services.AddCors(options => |
|
||||
{ |
|
||||
options.AddPolicy(name: CORS_POLICY, |
|
||||
builder => |
|
||||
{ |
|
||||
builder.WithOrigins(baseUrlConfig.WebBase.Replace("host.docker.internal", "localhost").TrimEnd('/')); |
|
||||
builder.AllowAnyMethod(); |
|
||||
builder.AllowAnyHeader(); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
services.AddControllers(); |
|
||||
services.AddMediatR(typeof(CatalogItem).Assembly); |
|
||||
|
|
||||
services.AddAutoMapper(typeof(Startup).Assembly); |
|
||||
services.AddSwaggerGen(c => |
|
||||
{ |
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); |
|
||||
c.EnableAnnotations(); |
|
||||
c.SchemaFilter<CustomSchemaFilters>(); |
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|
||||
{ |
|
||||
Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n
|
|
||||
Enter 'Bearer' [space] and then your token in the text input below. |
|
||||
\r\n\r\nExample: 'Bearer 12345abcdef'",
|
|
||||
Name = "Authorization", |
|
||||
In = ParameterLocation.Header, |
|
||||
Type = SecuritySchemeType.ApiKey, |
|
||||
Scheme = "Bearer" |
|
||||
}); |
|
||||
|
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement() |
|
||||
{ |
|
||||
{ |
|
||||
new OpenApiSecurityScheme |
|
||||
{ |
|
||||
Reference = new OpenApiReference |
|
||||
{ |
|
||||
Type = ReferenceType.SecurityScheme, |
|
||||
Id = "Bearer" |
|
||||
}, |
|
||||
Scheme = "oauth2", |
|
||||
Name = "Bearer", |
|
||||
In = ParameterLocation.Header, |
|
||||
|
|
||||
}, |
|
||||
new List<string>() |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) |
|
||||
{ |
|
||||
if (env.IsDevelopment()) |
|
||||
{ |
|
||||
app.UseDeveloperExceptionPage(); |
|
||||
} |
|
||||
|
|
||||
app.UseMiddleware<ExceptionMiddleware>(); |
|
||||
|
|
||||
app.UseHttpsRedirection(); |
|
||||
|
|
||||
app.UseRouting(); |
|
||||
|
|
||||
app.UseCors(CORS_POLICY); |
|
||||
|
|
||||
app.UseAuthorization(); |
|
||||
|
|
||||
// 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.UseEndpoints(endpoints => |
|
||||
{ |
|
||||
endpoints.MapControllers(); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
@ -1,49 +1,198 @@ |
|||||
using System; |
using System.Net.Mime; |
||||
using System.Threading.Tasks; |
using Ardalis.ListStartupServices; |
||||
using Microsoft.AspNetCore.Hosting; |
using BlazorAdmin; |
||||
|
using BlazorAdmin.Services; |
||||
|
using Blazored.LocalStorage; |
||||
|
using BlazorShared; |
||||
|
using Microsoft.AspNetCore.Authentication.Cookies; |
||||
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks; |
||||
using Microsoft.AspNetCore.Identity; |
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.AspNetCore.Mvc.ApplicationModels; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.eShopWeb; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
using Microsoft.eShopWeb.Infrastructure.Data; |
using Microsoft.eShopWeb.Infrastructure.Data; |
||||
using Microsoft.eShopWeb.Infrastructure.Identity; |
using Microsoft.eShopWeb.Infrastructure.Identity; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.eShopWeb.Web; |
||||
using Microsoft.Extensions.Hosting; |
using Microsoft.eShopWeb.Web.Configuration; |
||||
using Microsoft.Extensions.Logging; |
using Microsoft.eShopWeb.Web.HealthChecks; |
||||
|
using Microsoft.Extensions.Diagnostics.HealthChecks; |
||||
|
|
||||
namespace Microsoft.eShopWeb.Web; |
var builder = WebApplication.CreateBuilder(args); |
||||
|
|
||||
public class Program |
builder.Logging.AddConsole(); |
||||
|
|
||||
|
// 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
|
||||
|
builder.Services.AddDbContext<CatalogContext>(c => |
||||
|
c.UseSqlServer(builder.Configuration.GetConnectionString("CatalogConnection"))); |
||||
|
|
||||
|
// Add Identity DbContext
|
||||
|
builder.Services.AddDbContext<AppIdentityDbContext>(options => |
||||
|
options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityConnection"))); |
||||
|
|
||||
|
builder.Services.AddCookieSettings(); |
||||
|
|
||||
|
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) |
||||
|
.AddCookie(options => |
||||
{ |
{ |
||||
public static async Task Main(string[] args) |
options.Cookie.HttpOnly = true; |
||||
|
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; |
||||
|
options.Cookie.SameSite = SameSiteMode.Lax; |
||||
|
}); |
||||
|
|
||||
|
builder.Services.AddIdentity<ApplicationUser, IdentityRole>() |
||||
|
.AddDefaultUI() |
||||
|
.AddEntityFrameworkStores<AppIdentityDbContext>() |
||||
|
.AddDefaultTokenProviders(); |
||||
|
|
||||
|
builder.Services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>(); |
||||
|
|
||||
|
builder.Services.AddCoreServices(builder.Configuration); |
||||
|
builder.Services.AddWebServices(builder.Configuration); |
||||
|
|
||||
|
// Add memory cache services
|
||||
|
builder.Services.AddMemoryCache(); |
||||
|
builder.Services.AddRouting(options => |
||||
{ |
{ |
||||
var host = CreateHostBuilder(args) |
// Replace the type and the name used to refer to it with your own
|
||||
.Build(); |
// IOutboundParameterTransformer implementation
|
||||
|
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer); |
||||
|
}); |
||||
|
|
||||
using (var scope = host.Services.CreateScope()) |
builder.Services.AddMvc(options => |
||||
{ |
{ |
||||
var services = scope.ServiceProvider; |
options.Conventions.Add(new RouteTokenTransformerConvention( |
||||
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); |
new SlugifyParameterTransformer())); |
||||
try |
|
||||
|
}); |
||||
|
builder.Services.AddControllersWithViews(); |
||||
|
builder.Services.AddRazorPages(options => |
||||
{ |
{ |
||||
var catalogContext = services.GetRequiredService<CatalogContext>(); |
options.Conventions.AuthorizePage("/Basket/Checkout"); |
||||
await CatalogContextSeed.SeedAsync(catalogContext, loggerFactory); |
}); |
||||
|
builder.Services.AddHttpContextAccessor(); |
||||
|
builder.Services |
||||
|
.AddHealthChecks() |
||||
|
.AddCheck<ApiHealthCheck>("api_health_check", tags: new[] { "apiHealthCheck" }) |
||||
|
.AddCheck<HomePageHealthCheck>("home_page_health_check", tags: new[] { "homePageHealthCheck" }); |
||||
|
builder.Services.Configure<ServiceConfig>(config => |
||||
|
{ |
||||
|
config.Services = new List<ServiceDescriptor>(builder.Services); |
||||
|
config.Path = "/allservices"; |
||||
|
}); |
||||
|
|
||||
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>(); |
// blazor configuration
|
||||
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>(); |
var configSection = builder.Configuration.GetRequiredSection(BaseUrlConfiguration.CONFIG_NAME); |
||||
await AppIdentityDbContextSeed.SeedAsync(userManager, roleManager); |
builder.Services.Configure<BaseUrlConfiguration>(configSection); |
||||
|
var baseUrlConfig = configSection.Get<BaseUrlConfiguration>(); |
||||
|
|
||||
|
// Blazor Admin Required Services for Prerendering
|
||||
|
builder.Services.AddScoped<HttpClient>(s => new HttpClient |
||||
|
{ |
||||
|
BaseAddress = new Uri(baseUrlConfig.WebBase) |
||||
|
}); |
||||
|
|
||||
|
// add blazor services
|
||||
|
builder.Services.AddBlazoredLocalStorage(); |
||||
|
builder.Services.AddServerSideBlazor(); |
||||
|
|
||||
|
|
||||
|
builder.Services.AddScoped<ToastService>(); |
||||
|
builder.Services.AddScoped<HttpService>(); |
||||
|
builder.Services.AddBlazorServices(); |
||||
|
|
||||
|
builder.Services.AddDatabaseDeveloperPageExceptionFilter(); |
||||
|
|
||||
|
//_services = services; // used to debug registered services
|
||||
|
|
||||
|
var app = builder.Build(); |
||||
|
|
||||
|
app.Logger.LogInformation("App created..."); |
||||
|
|
||||
|
var catalogBaseUrl = builder.Configuration.GetValue(typeof(string), "CatalogBaseUrl") as string; |
||||
|
if (!string.IsNullOrEmpty(catalogBaseUrl)) |
||||
|
{ |
||||
|
app.Use((context, next) => |
||||
|
{ |
||||
|
context.Request.PathBase = new PathString(catalogBaseUrl); |
||||
|
return next(); |
||||
|
}); |
||||
} |
} |
||||
catch (Exception ex) |
|
||||
|
app.UseHealthChecks("/health", |
||||
|
new HealthCheckOptions |
||||
|
{ |
||||
|
ResponseWriter = async (context, report) => |
||||
{ |
{ |
||||
var logger = loggerFactory.CreateLogger<Program>(); |
var result = new |
||||
logger.LogError(ex, "An error occurred seeding the DB."); |
{ |
||||
|
status = report.Status.ToString(), |
||||
|
errors = report.Entries.Select(e => new |
||||
|
{ |
||||
|
key = e.Key, |
||||
|
value = Enum.GetName(typeof(HealthStatus), e.Value.Status) |
||||
|
}) |
||||
|
}.ToJson(); |
||||
|
context.Response.ContentType = MediaTypeNames.Application.Json; |
||||
|
await context.Response.WriteAsync(result); |
||||
} |
} |
||||
|
}); |
||||
|
if (app.Environment.IsDevelopment()) |
||||
|
{ |
||||
|
app.Logger.LogInformation("Adding Development middleware..."); |
||||
|
app.UseDeveloperExceptionPage(); |
||||
|
app.UseShowAllServicesMiddleware(); |
||||
|
app.UseMigrationsEndPoint(); |
||||
|
app.UseWebAssemblyDebugging(); |
||||
} |
} |
||||
|
else |
||||
host.Run(); |
{ |
||||
|
app.Logger.LogInformation("Adding non-Development middleware..."); |
||||
|
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(); |
||||
} |
} |
||||
|
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) => |
app.UseHttpsRedirection(); |
||||
Host.CreateDefaultBuilder(args) |
app.UseBlazorFrameworkFiles(); |
||||
.ConfigureWebHostDefaults(webBuilder => |
app.UseStaticFiles(); |
||||
|
app.UseRouting(); |
||||
|
|
||||
|
app.UseCookiePolicy(); |
||||
|
app.UseAuthentication(); |
||||
|
app.UseAuthorization(); |
||||
|
|
||||
|
app.UseEndpoints(endpoints => |
||||
{ |
{ |
||||
webBuilder.UseStartup<Startup>(); |
endpoints.MapControllerRoute("default", "{controller:slugify=Home}/{action:slugify=Index}/{id?}"); |
||||
|
endpoints.MapRazorPages(); |
||||
|
endpoints.MapHealthChecks("home_page_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("homePageHealthCheck") }); |
||||
|
endpoints.MapHealthChecks("api_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("apiHealthCheck") }); |
||||
|
//endpoints.MapBlazorHub("/admin");
|
||||
|
endpoints.MapFallbackToFile("index.html"); |
||||
}); |
}); |
||||
|
|
||||
|
app.Logger.LogInformation("Seeding Database..."); |
||||
|
|
||||
|
using (var scope = app.Services.CreateScope()) |
||||
|
{ |
||||
|
var scopedProvider = scope.ServiceProvider; |
||||
|
try |
||||
|
{ |
||||
|
var catalogContext = scopedProvider.GetRequiredService<CatalogContext>(); |
||||
|
await CatalogContextSeed.SeedAsync(catalogContext, app.Logger); |
||||
|
|
||||
|
var userManager = scopedProvider.GetRequiredService<UserManager<ApplicationUser>>(); |
||||
|
var roleManager = scopedProvider.GetRequiredService<RoleManager<IdentityRole>>(); |
||||
|
await AppIdentityDbContextSeed.SeedAsync(userManager, roleManager); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
app.Logger.LogError(ex, "An error occurred seeding the DB."); |
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
app.Logger.LogInformation("LAUNCHING"); |
||||
|
app.Run(); |
||||
|
|||||
@ -1,241 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.IO; |
|
||||
using System.Linq; |
|
||||
using System.Net.Http; |
|
||||
using System.Net.Mime; |
|
||||
using Ardalis.ListStartupServices; |
|
||||
using BlazorAdmin; |
|
||||
using BlazorAdmin.Services; |
|
||||
using Blazored.LocalStorage; |
|
||||
using BlazorShared; |
|
||||
using Microsoft.AspNetCore.Authentication.Cookies; |
|
||||
using Microsoft.AspNetCore.Builder; |
|
||||
using Microsoft.AspNetCore.DataProtection; |
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks; |
|
||||
using Microsoft.AspNetCore.Hosting; |
|
||||
using Microsoft.AspNetCore.Http; |
|
||||
using Microsoft.AspNetCore.Identity; |
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels; |
|
||||
using Microsoft.EntityFrameworkCore; |
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|
||||
using Microsoft.eShopWeb.Infrastructure.Data; |
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity; |
|
||||
using Microsoft.eShopWeb.Web.Configuration; |
|
||||
using Microsoft.eShopWeb.Web.HealthChecks; |
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks; |
|
||||
using Microsoft.Extensions.Hosting; |
|
||||
|
|
||||
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);
|
|
||||
} |
|
||||
|
|
||||
public void ConfigureDockerServices(IServiceCollection services) |
|
||||
{ |
|
||||
services.AddDataProtection() |
|
||||
.SetApplicationName("eshopwebmvc") |
|
||||
.PersistKeysToFileSystem(new DirectoryInfo(@"./")); |
|
||||
|
|
||||
ConfigureDevelopmentServices(services); |
|
||||
} |
|
||||
|
|
||||
private void ConfigureInMemoryDatabases(IServiceCollection services) |
|
||||
{ |
|
||||
// use in-memory database
|
|
||||
services.AddDbContext<CatalogContext>(c => |
|
||||
c.UseInMemoryDatabase("Catalog")); |
|
||||
|
|
||||
// Add Identity DbContext
|
|
||||
services.AddDbContext<AppIdentityDbContext>(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<CatalogContext>(c => |
|
||||
c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection"))); |
|
||||
|
|
||||
// Add Identity DbContext
|
|
||||
services.AddDbContext<AppIdentityDbContext>(options => |
|
||||
options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"))); |
|
||||
|
|
||||
ConfigureServices(services); |
|
||||
} |
|
||||
|
|
||||
public void ConfigureTestingServices(IServiceCollection services) |
|
||||
{ |
|
||||
ConfigureInMemoryDatabases(services); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
|
||||
public void ConfigureServices(IServiceCollection services) |
|
||||
{ |
|
||||
services.AddCookieSettings(); |
|
||||
|
|
||||
|
|
||||
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) |
|
||||
.AddCookie(options => |
|
||||
{ |
|
||||
options.Cookie.HttpOnly = true; |
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; |
|
||||
options.Cookie.SameSite = SameSiteMode.Lax; |
|
||||
}); |
|
||||
|
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>() |
|
||||
.AddDefaultUI() |
|
||||
.AddEntityFrameworkStores<AppIdentityDbContext>() |
|
||||
.AddDefaultTokenProviders(); |
|
||||
|
|
||||
services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>(); |
|
||||
|
|
||||
services.AddCoreServices(Configuration); |
|
||||
services.AddWebServices(Configuration); |
|
||||
|
|
||||
// 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())); |
|
||||
|
|
||||
}); |
|
||||
services.AddControllersWithViews(); |
|
||||
services.AddRazorPages(options => |
|
||||
{ |
|
||||
options.Conventions.AuthorizePage("/Basket/Checkout"); |
|
||||
}); |
|
||||
services.AddHttpContextAccessor(); |
|
||||
services |
|
||||
.AddHealthChecks() |
|
||||
.AddCheck<ApiHealthCheck>("api_health_check", tags: new[] { "apiHealthCheck" }) |
|
||||
.AddCheck<HomePageHealthCheck>("home_page_health_check", tags: new[] { "homePageHealthCheck" }); |
|
||||
services.Configure<ServiceConfig>(config => |
|
||||
{ |
|
||||
config.Services = new List<ServiceDescriptor>(services); |
|
||||
|
|
||||
config.Path = "/allservices"; |
|
||||
}); |
|
||||
|
|
||||
var configSection = Configuration.GetRequiredSection(BaseUrlConfiguration.CONFIG_NAME); |
|
||||
services.Configure<BaseUrlConfiguration>(configSection); |
|
||||
var baseUrlConfig = configSection.Get<BaseUrlConfiguration>(); |
|
||||
|
|
||||
// Blazor Admin Required Services for Prerendering
|
|
||||
services.AddScoped<HttpClient>(s => new HttpClient |
|
||||
{ |
|
||||
BaseAddress = new Uri(baseUrlConfig.WebBase) |
|
||||
}); |
|
||||
|
|
||||
// add blazor services
|
|
||||
services.AddBlazoredLocalStorage(); |
|
||||
services.AddServerSideBlazor(); |
|
||||
|
|
||||
|
|
||||
services.AddScoped<ToastService>(); |
|
||||
services.AddScoped<HttpService>(); |
|
||||
services.AddBlazorServices(); |
|
||||
|
|
||||
services.AddDatabaseDeveloperPageExceptionFilter(); |
|
||||
|
|
||||
_services = services; // used to debug registered services
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) |
|
||||
{ |
|
||||
var catalogBaseUrl = Configuration.GetValue(typeof(string), "CatalogBaseUrl") as string; |
|
||||
if (!string.IsNullOrEmpty(catalogBaseUrl)) |
|
||||
{ |
|
||||
app.Use((context, next) => |
|
||||
{ |
|
||||
context.Request.PathBase = new PathString(catalogBaseUrl); |
|
||||
return next(); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
app.UseHealthChecks("/health", |
|
||||
new HealthCheckOptions |
|
||||
{ |
|
||||
ResponseWriter = async (context, report) => |
|
||||
{ |
|
||||
var result = new |
|
||||
{ |
|
||||
status = report.Status.ToString(), |
|
||||
errors = report.Entries.Select(e => new |
|
||||
{ |
|
||||
key = e.Key, |
|
||||
value = Enum.GetName(typeof(HealthStatus), e.Value.Status) |
|
||||
}) |
|
||||
}.ToJson(); |
|
||||
context.Response.ContentType = MediaTypeNames.Application.Json; |
|
||||
await context.Response.WriteAsync(result); |
|
||||
} |
|
||||
}); |
|
||||
if (env.IsDevelopment()) |
|
||||
{ |
|
||||
app.UseDeveloperExceptionPage(); |
|
||||
app.UseShowAllServicesMiddleware(); |
|
||||
app.UseMigrationsEndPoint(); |
|
||||
app.UseWebAssemblyDebugging(); |
|
||||
} |
|
||||
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.UseBlazorFrameworkFiles(); |
|
||||
app.UseStaticFiles(); |
|
||||
app.UseRouting(); |
|
||||
|
|
||||
app.UseCookiePolicy(); |
|
||||
app.UseAuthentication(); |
|
||||
app.UseAuthorization(); |
|
||||
|
|
||||
app.UseEndpoints(endpoints => |
|
||||
{ |
|
||||
endpoints.MapControllerRoute("default", "{controller:slugify=Home}/{action:slugify=Index}/{id?}"); |
|
||||
endpoints.MapRazorPages(); |
|
||||
endpoints.MapHealthChecks("home_page_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("homePageHealthCheck") }); |
|
||||
endpoints.MapHealthChecks("api_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("apiHealthCheck") }); |
|
||||
//endpoints.MapBlazorHub("/admin");
|
|
||||
endpoints.MapFallbackToFile("index.html"); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,78 +1,43 @@ |
|||||
using System; |
using Microsoft.AspNetCore.Hosting; |
||||
using Microsoft.AspNetCore.Hosting; |
|
||||
using Microsoft.AspNetCore.Identity; |
|
||||
using Microsoft.AspNetCore.Mvc.Testing; |
using Microsoft.AspNetCore.Mvc.Testing; |
||||
using Microsoft.EntityFrameworkCore; |
using Microsoft.EntityFrameworkCore; |
||||
using Microsoft.eShopWeb.Infrastructure.Data; |
using Microsoft.eShopWeb.Infrastructure.Data; |
||||
using Microsoft.eShopWeb.Infrastructure.Identity; |
using Microsoft.eShopWeb.Infrastructure.Identity; |
||||
using Microsoft.eShopWeb.PublicApi; |
using Microsoft.eShopWeb.PublicApi.AuthEndpoints; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Logging; |
using Microsoft.Extensions.Hosting; |
||||
|
|
||||
namespace Microsoft.eShopWeb.FunctionalTests.PublicApi; |
namespace Microsoft.eShopWeb.FunctionalTests.PublicApi; |
||||
|
|
||||
public class ApiTestFixture : WebApplicationFactory<Startup> |
public class TestApiApplication : WebApplicationFactory<Authenticate> |
||||
{ |
{ |
||||
protected override void ConfigureWebHost(IWebHostBuilder builder) |
private readonly string _environment = "Testing"; |
||||
|
|
||||
|
protected override IHost CreateHost(IHostBuilder builder) |
||||
{ |
{ |
||||
builder.UseEnvironment("Testing"); |
builder.UseEnvironment(_environment); |
||||
|
|
||||
|
// Add mock/test services to the builder here
|
||||
builder.ConfigureServices(services => |
builder.ConfigureServices(services => |
||||
{ |
{ |
||||
services.AddEntityFrameworkInMemoryDatabase(); |
services.AddScoped(sp => |
||||
|
|
||||
// Create a new service provider.
|
|
||||
var provider = services |
|
||||
.AddEntityFrameworkInMemoryDatabase() |
|
||||
.BuildServiceProvider(); |
|
||||
|
|
||||
// Add a database context (ApplicationDbContext) using an in-memory
|
|
||||
// database for testing.
|
|
||||
services.AddDbContext<CatalogContext>(options => |
|
||||
{ |
{ |
||||
options.UseInMemoryDatabase("InMemoryDbForTesting"); |
// Replace SQLite with in-memory database for tests
|
||||
options.UseInternalServiceProvider(provider); |
return new DbContextOptionsBuilder<CatalogContext>() |
||||
|
.UseInMemoryDatabase("DbForPublicApi") |
||||
|
.UseApplicationServiceProvider(sp) |
||||
|
.Options; |
||||
}); |
}); |
||||
|
services.AddScoped(sp => |
||||
services.AddDbContext<AppIdentityDbContext>(options => |
|
||||
{ |
{ |
||||
options.UseInMemoryDatabase("Identity"); |
// Replace SQLite with in-memory database for tests
|
||||
options.UseInternalServiceProvider(provider); |
return new DbContextOptionsBuilder<AppIdentityDbContext>() |
||||
|
.UseInMemoryDatabase("IdentityDbForPublicApi") |
||||
|
.UseApplicationServiceProvider(sp) |
||||
|
.Options; |
||||
}); |
}); |
||||
|
|
||||
// Build the service provider.
|
|
||||
var sp = services.BuildServiceProvider(); |
|
||||
|
|
||||
// Create a scope to obtain a reference to the database
|
|
||||
// context (ApplicationDbContext).
|
|
||||
using (var scope = sp.CreateScope()) |
|
||||
{ |
|
||||
var scopedServices = scope.ServiceProvider; |
|
||||
var db = scopedServices.GetRequiredService<CatalogContext>(); |
|
||||
var loggerFactory = scopedServices.GetRequiredService<ILoggerFactory>(); |
|
||||
|
|
||||
var logger = scopedServices |
|
||||
.GetRequiredService<ILogger<ApiTestFixture>>(); |
|
||||
|
|
||||
// Ensure the database is created.
|
|
||||
db.Database.EnsureCreated(); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
// Seed the database with test data.
|
|
||||
CatalogContextSeed.SeedAsync(db, loggerFactory).Wait(); |
|
||||
|
|
||||
// seed sample user data
|
|
||||
var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>(); |
|
||||
var roleManager = scopedServices.GetRequiredService<RoleManager<IdentityRole>>(); |
|
||||
AppIdentityDbContextSeed.SeedAsync(userManager, roleManager).Wait(); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
logger.LogError(ex, $"An error occurred seeding the " + |
|
||||
"database with test messages. Error: {ex.Message}"); |
|
||||
} |
|
||||
} |
|
||||
}); |
}); |
||||
|
|
||||
|
return base.CreateHost(builder); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue