From 8c2ca8dbd9b0f9149d2fdedd755e56e662f6e513 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 7 May 2023 22:21:52 -0700 Subject: [PATCH] Make WebMVC use the service common helpers --- src/Web/WebMVC/Extensions/Extensions.cs | 86 +++++++++++++++ src/Web/WebMVC/Program.cs | 132 ++---------------------- src/Web/WebMVC/WebMVC.csproj | 13 +-- src/Web/WebMVC/appsettings.json | 7 ++ src/Web/WebMVC/globalusings.cs | 5 +- 5 files changed, 105 insertions(+), 138 deletions(-) create mode 100644 src/Web/WebMVC/Extensions/Extensions.cs diff --git a/src/Web/WebMVC/Extensions/Extensions.cs b/src/Web/WebMVC/Extensions/Extensions.cs new file mode 100644 index 000000000..58ad01203 --- /dev/null +++ b/src/Web/WebMVC/Extensions/Extensions.cs @@ -0,0 +1,86 @@ +// Fix samesite issue when running eShop from docker-compose locally as by default http protocol is being used +// Refer to https://github.com/dotnet-architecture/eShopOnContainers/issues/1391 +internal static class Extensions +{ + public static void AddHealthChecks(this WebApplicationBuilder builder) + { + builder.Services.AddHealthChecks() + .AddUrlGroup(_ => new Uri(builder.Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); + } + + public static void AddApplicationSevices(this WebApplicationBuilder builder) + { + builder.Services.Configure(builder.Configuration) + .AddSession() + .AddDistributedMemoryCache(); + + if (builder.Configuration["DPConnectionString"] is string redisConnection) + { + builder.Services.AddDataProtection(opts => + { + opts.ApplicationDiscriminator = "eshop.webmvc"; + }) + .PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(redisConnection), "DataProtection-Keys"); + } + } + + // Adds all Http client services + public static void AddHttpClientServices(this WebApplicationBuilder builder) + { + // Register delegating handlers + builder.Services.AddTransient() + .AddTransient(); + + // Add http client services + builder.Services.AddHttpClient() + .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Sample. Default lifetime is 2 minutes + .AddHttpMessageHandler(); + + builder.Services.AddHttpClient(); + + builder.Services.AddHttpClient() + .AddHttpMessageHandler() + .AddHttpMessageHandler(); + + + //add custom application services + builder.Services.AddTransient, IdentityParser>(); + } + + public static void AddAuthenticationServices(this WebApplicationBuilder builder) + { + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); + + var identityUrl = builder.Configuration.GetRequiredValue("IdentityUrl"); + var callBackUrl = builder.Configuration.GetRequiredValue("CallBackUrl"); + var sessionCookieLifetime = builder.Configuration.GetValue("SessionCookieLifetimeMinutes", 60); + + // Add Authentication services + + builder.Services.AddAuthentication(options => + { + options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; + }) + .AddCookie(options => options.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime)) + .AddOpenIdConnect(options => + { + options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.Authority = identityUrl; + options.SignedOutRedirectUri = callBackUrl; + options.ClientId = "mvc"; + options.ClientSecret = "secret"; + options.ResponseType = "code"; + options.SaveTokens = true; + options.GetClaimsFromUserInfoEndpoint = true; + options.RequireHttpsMetadata = false; + options.Scope.Add("openid"); + options.Scope.Add("profile"); + options.Scope.Add("orders"); + options.Scope.Add("basket"); + options.Scope.Add("webshoppingagg"); + options.Scope.Add("orders.signalrhub"); + options.Scope.Add("webhooks"); + }); + } +} diff --git a/src/Web/WebMVC/Program.cs b/src/Web/WebMVC/Program.cs index ce7d33208..fac986d73 100644 --- a/src/Web/WebMVC/Program.cs +++ b/src/Web/WebMVC/Program.cs @@ -1,34 +1,21 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddControllersWithViews(); - -AddApplicationInsights(builder); -AddHealthChecks(builder); -AddCustomMvc(builder); -AddHttpClientServices(builder); -AddCustomAuthentication(builder); -builder.WebHost.CaptureStartupErrors(false); +builder.AddServiceDefaults(); -var app = builder.Build(); +builder.Services.AddControllersWithViews(); -JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); -if (!app.Environment.IsDevelopment()) -{ - app.UseExceptionHandler("/Error"); -} +builder.AddHealthChecks(); +builder.AddApplicationSevices(); +builder.AddHttpClientServices(); +builder.AddAuthenticationServices(); -var pathBase = builder.Configuration["PATH_BASE"]; +var app = builder.Build(); -if (!string.IsNullOrEmpty(pathBase)) -{ - app.UsePathBase(pathBase); -} +app.UseServiceDefaults(); app.UseStaticFiles(); app.UseSession(); -WebContextSeed.Seed(app, app.Environment); - // Fix samesite issue when running eShop from docker-compose locally as by default http protocol is being used // Refer to https://github.com/dotnet-architecture/eShopOnContainers/issues/1391 app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax }); @@ -41,106 +28,7 @@ app.UseAuthorization(); app.MapControllerRoute("default", "{controller=Catalog}/{action=Index}/{id?}"); app.MapControllerRoute("defaultError", "{controller=Error}/{action=Error}"); app.MapControllers(); -app.MapHealthChecks("/liveness", new HealthCheckOptions -{ - Predicate = r => r.Name.Contains("self") -}); -app.MapHealthChecks("/hc", new HealthCheckOptions() -{ - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse -}); - -await app.RunAsync(); - -static void AddApplicationInsights(WebApplicationBuilder builder) -{ - builder.Services.AddApplicationInsightsTelemetry(builder.Configuration); - builder.Services.AddApplicationInsightsKubernetesEnricher(); -} - -static void AddHealthChecks(WebApplicationBuilder builder) -{ - builder.Services.AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddUrlGroup(_ => new Uri(builder.Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); -} - -static void AddCustomMvc(WebApplicationBuilder builder) -{ - builder.Services.Configure(builder.Configuration) - .AddSession() - .AddDistributedMemoryCache(); - if (builder.Configuration.GetValue("IsClusterEnv") == bool.TrueString) - { - builder.Services.AddDataProtection(opts => - { - opts.ApplicationDiscriminator = "eshop.webmvc"; - }) - .PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(builder.Configuration["DPConnectionString"]), "DataProtection-Keys"); - } -} - -// Adds all Http client services -static void AddHttpClientServices(WebApplicationBuilder builder) -{ - builder.Services.AddHttpContextAccessor(); - - //register delegating handlers - builder.Services.AddTransient() - .AddTransient(); - - //set 5 min as the lifetime for each HttpMessageHandler int the pool - builder.Services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(TimeSpan.FromMinutes(5)); - - //add http client services - builder.Services.AddHttpClient() - .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Sample. Default lifetime is 2 minutes - .AddHttpMessageHandler(); - - builder.Services.AddHttpClient(); - - builder.Services.AddHttpClient() - .AddHttpMessageHandler() - .AddHttpMessageHandler(); - - - //add custom application services - builder.Services.AddTransient, IdentityParser>(); -} - -static void AddCustomAuthentication(WebApplicationBuilder builder) -{ - var identityUrl = builder.Configuration.GetValue("IdentityUrl"); - var callBackUrl = builder.Configuration.GetValue("CallBackUrl"); - var sessionCookieLifetime = builder.Configuration.GetValue("SessionCookieLifetimeMinutes", 60); - - // Add Authentication services +WebContextSeed.Seed(app, app.Environment); - builder.Services.AddAuthentication(options => - { - options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; - }) - .AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime)) - .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => - { - options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.Authority = identityUrl.ToString(); - options.SignedOutRedirectUri = callBackUrl.ToString(); - options.ClientId = "mvc"; - options.ClientSecret = "secret"; - options.ResponseType = "code"; - options.SaveTokens = true; - options.GetClaimsFromUserInfoEndpoint = true; - options.RequireHttpsMetadata = false; - options.Scope.Add("openid"); - options.Scope.Add("profile"); - options.Scope.Add("orders"); - options.Scope.Add("basket"); - options.Scope.Add("webshoppingagg"); - options.Scope.Add("orders.signalrhub"); - options.Scope.Add("webhooks"); - }); -} +await app.RunAsync(); diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index e0b3fff05..cad1a70be 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -5,8 +5,6 @@ aspnet-Microsoft.eShopOnContainers-946ae052-8305-4a99-965b-ec8636ddbae3 ..\..\..\docker-compose.dcproj 3.0 - false - true @@ -24,21 +22,12 @@ - - - - - - - - - - + diff --git a/src/Web/WebMVC/appsettings.json b/src/Web/WebMVC/appsettings.json index ba45dbdd8..bcf097610 100644 --- a/src/Web/WebMVC/appsettings.json +++ b/src/Web/WebMVC/appsettings.json @@ -1,4 +1,11 @@ { + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", "PurchaseUrl": "http://localhost:5229", "SignalrHubUrl": "http://localhost:5229", "IdentityUrl": "http://localhost:5223", diff --git a/src/Web/WebMVC/globalusings.cs b/src/Web/WebMVC/globalusings.cs index 1fe624e28..d315d7434 100644 --- a/src/Web/WebMVC/globalusings.cs +++ b/src/Web/WebMVC/globalusings.cs @@ -15,14 +15,12 @@ global using System.Text.Json; global using System.Text.Json.Serialization; global using System.Threading; global using System.Threading.Tasks; -global using HealthChecks.UI.Client; global using Microsoft.AspNetCore.Authentication; global using Microsoft.AspNetCore.Authentication.Cookies; global using Microsoft.AspNetCore.Authentication.OpenIdConnect; global using Microsoft.AspNetCore.Authorization; global using Microsoft.AspNetCore.Builder; global using Microsoft.AspNetCore.DataProtection; -global using Microsoft.AspNetCore.Diagnostics.HealthChecks; global using Microsoft.AspNetCore.Hosting; global using Microsoft.AspNetCore.Http; global using Microsoft.AspNetCore.Identity; @@ -37,10 +35,9 @@ global using Microsoft.eShopOnContainers.WebMVC.ViewModels.CatalogViewModels; global using Microsoft.eShopOnContainers.WebMVC.ViewModels.Pagination; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; -global using Microsoft.Extensions.Diagnostics.HealthChecks; -global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Options; +global using Services.Common; global using StackExchange.Redis; global using WebMVC.Infrastructure; global using WebMVC.Services.ModelDTOs;