From acd9a6d04b5288e80dfd228aecb71d80a77231c4 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 5 May 2023 20:05:45 -0700 Subject: [PATCH] Clean up the identity project and make it use services common --- .../Identity/Identity.API/GlobalUsings.cs | 46 ++++-------- .../Identity.API/IWebHostExtensions.cs | 69 ----------------- .../Identity/Identity.API/Identity.API.csproj | 74 ++++++++----------- src/Services/Identity/Identity.API/Program.cs | 38 +++------- .../Identity/Identity.API/appsettings.json | 12 +-- src/Services/Identity/Identity.API/web.config | 17 ----- .../Services.Common/CommonExtensions.cs | 15 +++- 7 files changed, 76 insertions(+), 195 deletions(-) delete mode 100644 src/Services/Identity/Identity.API/IWebHostExtensions.cs delete mode 100644 src/Services/Identity/Identity.API/web.config diff --git a/src/Services/Identity/Identity.API/GlobalUsings.cs b/src/Services/Identity/Identity.API/GlobalUsings.cs index a4ecca85f..439583c53 100644 --- a/src/Services/Identity/Identity.API/GlobalUsings.cs +++ b/src/Services/Identity/Identity.API/GlobalUsings.cs @@ -1,7 +1,11 @@ -global using Azure.Core; -global using Azure.Identity; -global using HealthChecks.UI.Client; -global using IdentityModel; +global using System; +global using System.Collections.Generic; +global using System.ComponentModel.DataAnnotations; +global using System.IdentityModel.Tokens.Jwt; +global using System.Linq; +global using System.Security.Claims; +global using System.Text.RegularExpressions; +global using System.Threading.Tasks; global using Duende.IdentityServer; global using Duende.IdentityServer.Configuration; global using Duende.IdentityServer.Events; @@ -10,53 +14,33 @@ global using Duende.IdentityServer.Models; global using Duende.IdentityServer.Services; global using Duende.IdentityServer.Stores; global using Duende.IdentityServer.Validation; +global using IdentityModel; global using Microsoft.AspNetCore.Authentication; global using Microsoft.AspNetCore.Authorization; global using Microsoft.AspNetCore.Builder; -global using Microsoft.AspNetCore.Diagnostics.HealthChecks; global using Microsoft.AspNetCore.Hosting; -global using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +global using Microsoft.AspNetCore.Http; global using Microsoft.AspNetCore.Identity; -global using Microsoft.AspNetCore.Mvc.Rendering; +global using Microsoft.AspNetCore.Identity.EntityFrameworkCore; global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Mvc.Filters; +global using Microsoft.AspNetCore.Mvc.Rendering; +global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore.Infrastructure; global using Microsoft.EntityFrameworkCore.Metadata; global using Microsoft.EntityFrameworkCore.Migrations; -global using Microsoft.EntityFrameworkCore; - global using Microsoft.eShopOnContainers.Services.Identity.API; -global using Microsoft.eShopOnContainers.Services.Identity.API.Data; global using Microsoft.eShopOnContainers.Services.Identity.API.Configuration; +global using Microsoft.eShopOnContainers.Services.Identity.API.Data; global using Microsoft.eShopOnContainers.Services.Identity.API.Models; global using Microsoft.eShopOnContainers.Services.Identity.API.Services; 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 Polly; -global using System.Collections.Generic; -global using System.ComponentModel.DataAnnotations; -global using System.Data.SqlClient; -global using System.IdentityModel.Tokens.Jwt; -global using System.Linq; -global using System.Security.Claims; -global using System.Text.RegularExpressions; -global using System.Threading.Tasks; -global using System; -global using Microsoft.AspNetCore.Http; - - - - - - - - - - +global using Services.Common; diff --git a/src/Services/Identity/Identity.API/IWebHostExtensions.cs b/src/Services/Identity/Identity.API/IWebHostExtensions.cs deleted file mode 100644 index a9e002d74..000000000 --- a/src/Services/Identity/Identity.API/IWebHostExtensions.cs +++ /dev/null @@ -1,69 +0,0 @@ -namespace Microsoft.AspNetCore.Hosting -{ - public static class IWebHostExtensions - { - public static bool IsInKubernetes(this IWebHost webHost) - { - var cfg = webHost.Services.GetService(); - var orchestratorType = cfg.GetValue("OrchestratorType"); - return orchestratorType?.ToUpper() == "K8S"; - } - - public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext - { - var underK8s = webHost.IsInKubernetes(); - - using var scope = webHost.Services.CreateScope(); - var services = scope.ServiceProvider; - var logger = services.GetRequiredService>(); - var context = services.GetService(); - - try - { - logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name); - - if (underK8s) - { - InvokeSeeder(seeder, context, services); - } - else - { - var retries = 10; - var retry = Policy.Handle() - .WaitAndRetry( - retryCount: retries, - sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), - onRetry: (exception, timeSpan, retry, ctx) => - { - logger.LogWarning(exception, "[{prefix}] Error seeding database (attempt {retry} of {retries})", nameof(TContext), retry, retries); - }); - - //if the sql server container is not created on run docker compose this - //migration can't fail for network related exception. The retry options for DbContext only - //apply to transient exceptions - // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service) - retry.Execute(() => InvokeSeeder(seeder, context, services)); - } - - logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name); - } - catch (Exception ex) - { - logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name); - if (underK8s) - { - throw; // Rethrow under k8s because we rely on k8s to re-run the pod - } - } - - return webHost; - } - - private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) - where TContext : DbContext - { - context.Database.Migrate(); - seeder(context, services); - } - } -} diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 4afd80c1c..ee587a6bf 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -4,68 +4,54 @@ net7.0 aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5 ..\..\..\..\docker-compose.dcproj - false - true - - - - - - - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Services/Identity/Identity.API/Program.cs b/src/Services/Identity/Identity.API/Program.cs index c0fa8fa7c..c8a04cd73 100644 --- a/src/Services/Identity/Identity.API/Program.cs +++ b/src/Services/Identity/Identity.API/Program.cs @@ -1,19 +1,12 @@ var builder = WebApplication.CreateBuilder(args); -if (builder.Configuration.GetValue("UseVault", false)) -{ - TokenCredential credential = new ClientSecretCredential( - builder.Configuration["Vault:TenantId"], - builder.Configuration["Vault:ClientId"], - builder.Configuration["Vault:ClientSecret"]); - builder.Configuration.AddAzureKeyVault(new Uri($"https://{builder.Configuration["Vault:Name"]}.vault.azure.net/"), credential); -} +builder.AddServiceDefaults(); builder.Services.AddControllersWithViews(); -builder.Services.AddControllers(); -builder.Services.AddRazorPages(); -builder.Services.AddDbContext(options => options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityDb"))); +builder.Services.AddDbContext(options => + options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityDb"))); + builder.Services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); @@ -35,23 +28,25 @@ builder.Services.AddIdentityServer(options => .AddAspNetIdentity() .AddDeveloperSigningCredential(); // Not recommended for production - you need to store your key material somewhere secure -builder.Services.AddAuthentication(); builder.Services.AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddSqlServer(builder.Configuration.GetConnectionString("IdentityDb"), + .AddSqlServer(_ => + builder.Configuration.GetRequiredConnectionString("IdentityDb"), name: "IdentityDB-check", tags: new string[] { "IdentityDB" }); + builder.Services.AddTransient(); builder.Services.AddTransient, EFLoginService>(); builder.Services.AddTransient(); var app = builder.Build(); -var pathBase = builder.Configuration["PATH_BASE"]; -if (!string.IsNullOrEmpty(pathBase)) +if (!await app.CheckHealthAsync()) { - app.UsePathBase(pathBase); + return; } + +app.UseServiceDefaults(); + app.UseStaticFiles(); // This cookie policy fixes login issues with Chrome 80+ using HHTP @@ -61,15 +56,6 @@ app.UseIdentityServer(); app.UseAuthorization(); app.MapDefaultControllerRoute(); -app.MapHealthChecks("/hc", new HealthCheckOptions() -{ - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse -}); -app.MapHealthChecks("/liveness", new HealthCheckOptions -{ - Predicate = r => r.Name.Contains("self") -}); // Apply database migration automatically. Note that this approach is not // recommended for production scenarios. Consider generating SQL scripts from diff --git a/src/Services/Identity/Identity.API/appsettings.json b/src/Services/Identity/Identity.API/appsettings.json index 955033706..48e4ff569 100644 --- a/src/Services/Identity/Identity.API/appsettings.json +++ b/src/Services/Identity/Identity.API/appsettings.json @@ -1,4 +1,10 @@ { + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, "IsClusterEnv": "False", "MvcClient": "http://localhost:5100", "SpaClient": "http://localhost:5104", @@ -7,12 +13,6 @@ "ApplicationInsights": { "InstrumentationKey": "" }, - "UseVault": false, - "Vault": { - "Name": "eshop", - "ClientId": "your-client-id", - "ClientSecret": "your-client-secret" - }, "TokenLifetimeMinutes": 120, "PermanentTokenLifetimeDays": 365 } diff --git a/src/Services/Identity/Identity.API/web.config b/src/Services/Identity/Identity.API/web.config deleted file mode 100644 index a2cf1fe26..000000000 --- a/src/Services/Identity/Identity.API/web.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Services/Services.Common/CommonExtensions.cs b/src/Services/Services.Common/CommonExtensions.cs index b922d6cc4..2c8510b0b 100644 --- a/src/Services/Services.Common/CommonExtensions.cs +++ b/src/Services/Services.Common/CommonExtensions.cs @@ -292,7 +292,12 @@ public static class CommonExtensions // } // } - var eventBusSection = configuration.GetRequiredSection("EventBus"); + var eventBusSection = configuration.GetSection("EventBus"); + + if (!eventBusSection.Exists()) + { + return hcBuilder; + } return eventBusSection["ProviderName"]?.ToLowerInvariant() switch { @@ -340,7 +345,13 @@ public static class CommonExtensions // } // } - var eventBusSection = configuration.GetRequiredSection("EventBus"); + var eventBusSection = configuration.GetSection("EventBus"); + + if (eventBusSection.Exists()) + { + return services; + } + if (string.Equals(eventBusSection["ProviderName"], "ServiceBus", StringComparison.OrdinalIgnoreCase)) { services.AddSingleton(sp =>