diff --git a/AppyNox.sln b/AppyNox.sln index 10ffbc5d..bc77ab20 100644 --- a/AppyNox.sln +++ b/AppyNox.sln @@ -104,10 +104,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "Integra EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppyNox.Services.Sso.WebAPI.IntegrationTest", "src\Services\SsoService\Tests\IntegrationTests\AppyNox.Services.Sso.WebAPI.IntegrationTest\AppyNox.Services.Sso.WebAPI.IntegrationTest.csproj", "{6D36FEB5-B1D5-4E6D-B3B4-18531447D5F7}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{909B33DD-BC66-411C-9CDD-27FCFB39A11E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppyNox.Services.Coupon.Benchmark", "src\Services\CouponService\Tests\Benchmarks\AppyNox.Services.Coupon.Benchmark\AppyNox.Services.Coupon.Benchmark.csproj", "{BB4BC444-008B-475A-9A8D-6F64FFE6B67F}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Presentation", "Presentation", "{5C856BDB-DCFD-4B09-8AAB-24AFA598DB1D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppyNox.Services.Sso.Server.UI", "src\Services\SsoService\Presentation\AppyNox.Services.Sso.Server.UI\AppyNox.Services.Sso.Server.UI.csproj", "{BDF26F8F-070C-47F2-B270-A9D5198ED1DC}" @@ -168,6 +164,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\publish-nuget.yml = .github\workflows\publish-nuget.yml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{B85D7137-4A4F-4ADF-8A96-2C494C059913}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppyNox.ServiceDefaults", "src\Aspire\AppyNox.ServiceDefaults\AppyNox.ServiceDefaults.csproj", "{DD85F606-E42C-49FD-8086-04C9F5CA406F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppyNox.AppHost", "src\Aspire\AppyNox.AppHost\AppyNox.AppHost.csproj", "{94CD6A5F-15ED-4FF3-9C33-F08A5DC92755}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -306,10 +308,6 @@ Global {6D36FEB5-B1D5-4E6D-B3B4-18531447D5F7}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D36FEB5-B1D5-4E6D-B3B4-18531447D5F7}.Release|Any CPU.ActiveCfg = Release|Any CPU {6D36FEB5-B1D5-4E6D-B3B4-18531447D5F7}.Release|Any CPU.Build.0 = Release|Any CPU - {BB4BC444-008B-475A-9A8D-6F64FFE6B67F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BB4BC444-008B-475A-9A8D-6F64FFE6B67F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BB4BC444-008B-475A-9A8D-6F64FFE6B67F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BB4BC444-008B-475A-9A8D-6F64FFE6B67F}.Release|Any CPU.Build.0 = Release|Any CPU {BDF26F8F-070C-47F2-B270-A9D5198ED1DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BDF26F8F-070C-47F2-B270-A9D5198ED1DC}.Debug|Any CPU.Build.0 = Debug|Any CPU {BDF26F8F-070C-47F2-B270-A9D5198ED1DC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -330,6 +328,14 @@ Global {0B11E729-D546-487A-A5C6-9614AC5D6CF3}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B11E729-D546-487A-A5C6-9614AC5D6CF3}.Release|Any CPU.ActiveCfg = Release|Any CPU {0B11E729-D546-487A-A5C6-9614AC5D6CF3}.Release|Any CPU.Build.0 = Release|Any CPU + {DD85F606-E42C-49FD-8086-04C9F5CA406F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD85F606-E42C-49FD-8086-04C9F5CA406F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD85F606-E42C-49FD-8086-04C9F5CA406F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD85F606-E42C-49FD-8086-04C9F5CA406F}.Release|Any CPU.Build.0 = Release|Any CPU + {94CD6A5F-15ED-4FF3-9C33-F08A5DC92755}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94CD6A5F-15ED-4FF3-9C33-F08A5DC92755}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94CD6A5F-15ED-4FF3-9C33-F08A5DC92755}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94CD6A5F-15ED-4FF3-9C33-F08A5DC92755}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -383,8 +389,6 @@ Global {E6F09B37-DBB4-45BD-B81A-72A610BBE021} = {14E3528C-2F6B-4296-BAD1-E91F32F679EC} {5D153F77-0942-4DA5-8655-AEDB92339738} = {C17866BD-9B28-4516-B3D7-FCBEFE171801} {6D36FEB5-B1D5-4E6D-B3B4-18531447D5F7} = {5D153F77-0942-4DA5-8655-AEDB92339738} - {909B33DD-BC66-411C-9CDD-27FCFB39A11E} = {5BAC57A7-56E7-4E7C-9118-24F61870BA91} - {BB4BC444-008B-475A-9A8D-6F64FFE6B67F} = {909B33DD-BC66-411C-9CDD-27FCFB39A11E} {5C856BDB-DCFD-4B09-8AAB-24AFA598DB1D} = {AD2F15A2-813D-422E-A37D-BED8810752C6} {BDF26F8F-070C-47F2-B270-A9D5198ED1DC} = {5C856BDB-DCFD-4B09-8AAB-24AFA598DB1D} {8EA810B2-F47D-4E10-9E8A-DC9EA663DB69} = {AD2F15A2-813D-422E-A37D-BED8810752C6} @@ -395,6 +399,8 @@ Global {FC84AF5D-DCC5-46C4-A93C-6047FDDACF26} = {EE924FAE-1536-4E54-A2E0-6698107A548C} {A649C5A6-11AB-4716-A7A4-54FFD327179D} = {FC84AF5D-DCC5-46C4-A93C-6047FDDACF26} {B54046FA-AC1E-4644-9985-4C233E986F33} = {FC84AF5D-DCC5-46C4-A93C-6047FDDACF26} + {DD85F606-E42C-49FD-8086-04C9F5CA406F} = {B85D7137-4A4F-4ADF-8A96-2C494C059913} + {94CD6A5F-15ED-4FF3-9C33-F08A5DC92755} = {B85D7137-4A4F-4ADF-8A96-2C494C059913} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EA4F2302-DC43-4149-814A-609940BEC847} diff --git a/src/Aspire/AppyNox.AppHost/AppyNox.AppHost.csproj b/src/Aspire/AppyNox.AppHost/AppyNox.AppHost.csproj new file mode 100644 index 00000000..9ff4490a --- /dev/null +++ b/src/Aspire/AppyNox.AppHost/AppyNox.AppHost.csproj @@ -0,0 +1,31 @@ + + + + + + Exe + net8.0 + enable + enable + true + df1762e9-7e42-475a-a8af-7e1dc8bbc26d + + + + + + + + + + + + + + + + + + + + diff --git a/src/Aspire/AppyNox.AppHost/Program.cs b/src/Aspire/AppyNox.AppHost/Program.cs new file mode 100644 index 00000000..c66bae87 --- /dev/null +++ b/src/Aspire/AppyNox.AppHost/Program.cs @@ -0,0 +1,74 @@ +using Projects; + +var builder = DistributedApplication.CreateBuilder(args); +var configuration = builder.Configuration; + +var db = builder.AddPostgres("appynox-db") + .WithDataVolume("appynox-db-volume") + .WithPgAdmin(); + +var ssoDb = db.AddDatabase("appynox-sso-db", "AppyNox_Sso"); +var ssoSagaDb = db.AddDatabase("appynox-sso-saga-db", "AppyNox_Sso_Saga"); +var licenseDb = db.AddDatabase("appynox-license-db", "AppyNox_License"); +var couponDb = db.AddDatabase("appynox-coupon-db", "AppyNox_Coupon"); + +var redis = builder.AddRedis("appynox-cache") + .WithRedisInsight(); + +var consul = builder.AddContainer("appynox-consul", "") + .WithImageRegistry("hashicorp") + .WithImage("consul") + .WithHttpEndpoint(8500, 8500); + +var seq = builder.AddSeq("seq") + .ExcludeFromManifest(); + +// For NoxLogger +var appynoxSeq = builder.AddSeq("appynox-seq") + .ExcludeFromManifest(); + +var internalRabbitmqUsername = builder.AddParameter(configuration["MessageBroker:Internal:Username"] ?? "quest"); +var internalRabbitmqPassword = builder.AddParameter(configuration["MessageBroker:Internal:Password"] ?? "quest"); +var externalRabbitmqUsername = builder.AddParameter(configuration["MessageBroker:External:Username"] ?? "quest"); +var externalRabbitmqPassword = builder.AddParameter(configuration["MessageBroker:External:Password"] ?? "quest"); + +var internalRabbitmq = builder.AddRabbitMQ("appynox-rabbitmq", internalRabbitmqUsername, internalRabbitmqPassword, 5672) + .WithManagementPlugin(); + +var externalRabbitmq = builder.AddRabbitMQ("external-rabbitmq", externalRabbitmqUsername, externalRabbitmqPassword, port: 5673) + .WithManagementPlugin(); + +var ssoApi = builder.AddProject("appynox-sso-api") + .WithReference(redis) + .WithReference(internalRabbitmq) + .WithReference(externalRabbitmq) + .WithReference(ssoDb) + .WithReference(ssoSagaDb) + .WithReference(seq) + .WithReference(appynoxSeq) + .WaitFor(consul) + .WaitFor(internalRabbitmq) + .WaitFor(externalRabbitmq); + +var couponApi = builder.AddProject("appynox-coupon-api") + .WithReference(redis) + .WithReference(internalRabbitmq) + .WithReference(couponDb) + .WithReference(seq) + .WithReference(appynoxSeq) + .WaitFor(consul) + .WaitFor(internalRabbitmq); + +var licenseApi = builder.AddProject("appynox-license-api") + .WithReference(redis) + .WithReference(internalRabbitmq) + .WithReference(licenseDb) + .WithReference(seq) + .WithReference(appynoxSeq) + .WaitFor(consul) + .WaitFor(internalRabbitmq); + +var gateway = builder.AddProject("appynox-gateway") + .WaitFor(consul); + +builder.Build().Run(); diff --git a/src/Aspire/AppyNox.AppHost/Properties/launchSettings.json b/src/Aspire/AppyNox.AppHost/Properties/launchSettings.json new file mode 100644 index 00000000..9be0f4a2 --- /dev/null +++ b/src/Aspire/AppyNox.AppHost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17129;http://localhost:15159", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21103", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22077" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15159", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19083", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20162" + } + } + } +} diff --git a/src/Aspire/AppyNox.AppHost/appsettings.Development.json b/src/Aspire/AppyNox.AppHost/appsettings.Development.json new file mode 100644 index 00000000..9ef7fae7 --- /dev/null +++ b/src/Aspire/AppyNox.AppHost/appsettings.Development.json @@ -0,0 +1,24 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "MessageBroker": { + "Internal": { + "Username": "HappiInternalUsername", + "Password": "HappiInternalPassword" + }, + "External": { + "Username": "HappiExternalUsername", + "Password": "HappiExternalPassword" + } + }, + "Parameters": { + "HappiInternalUsername": "Happi", + "HappiInternalPassword": "Happi", + "HappiExternalUsername": "Happi", + "HappiExternalPassword": "Happi" + } +} diff --git a/src/Aspire/AppyNox.AppHost/appsettings.json b/src/Aspire/AppyNox.AppHost/appsettings.json new file mode 100644 index 00000000..31c092aa --- /dev/null +++ b/src/Aspire/AppyNox.AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/src/Aspire/AppyNox.ServiceDefaults/AppyNox.ServiceDefaults.csproj b/src/Aspire/AppyNox.ServiceDefaults/AppyNox.ServiceDefaults.csproj new file mode 100644 index 00000000..6c036a13 --- /dev/null +++ b/src/Aspire/AppyNox.ServiceDefaults/AppyNox.ServiceDefaults.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + true + + + + + + + + + + + + + + + diff --git a/src/Aspire/AppyNox.ServiceDefaults/Extensions.cs b/src/Aspire/AppyNox.ServiceDefaults/Extensions.cs new file mode 100644 index 00000000..0eab6796 --- /dev/null +++ b/src/Aspire/AppyNox.ServiceDefaults/Extensions.cs @@ -0,0 +1,120 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.Hosting +{ + // Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. + // This project should be referenced by each service project in your solution. + // To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults + public static class Extensions + { + public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.ConfigureOpenTelemetry(); + + builder.AddDefaultHealthChecks(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + + return builder; + } + + public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + .AddAspNetCoreInstrumentation() + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry().UseOtlpExporter(); + } + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) + { + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } + + return app; + } + } +} diff --git a/src/Services/.BaseService/AppyNox.Services.Base.API/ApiBuilder.cs b/src/Services/.BaseService/AppyNox.Services.Base.API/ApiBuilder.cs index b8fc4741..82268b5c 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.API/ApiBuilder.cs +++ b/src/Services/.BaseService/AppyNox.Services.Base.API/ApiBuilder.cs @@ -50,6 +50,8 @@ public static void ConfigureNoxApi(this WebApplication app, Action c { PerformAutoMapperChecks(app); } + + app.MapDefaultEndpoints(); } private static void ConfigureLocalization(this WebApplication app, ApiOptions options) diff --git a/src/Services/.BaseService/AppyNox.Services.Base.API/ApiServiceBuilder.cs b/src/Services/.BaseService/AppyNox.Services.Base.API/ApiServiceBuilder.cs index f55d1e92..c1228f11 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.API/ApiServiceBuilder.cs +++ b/src/Services/.BaseService/AppyNox.Services.Base.API/ApiServiceBuilder.cs @@ -6,10 +6,9 @@ using AppyNox.Services.Base.Infrastructure.Services.LoggerService; using Asp.Versioning; using Asp.Versioning.Conventions; -using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using Serilog; @@ -26,7 +25,7 @@ public class ApiServiceOptions [Required] public string SetupHostName { get; set; } public bool UseConsulKV { get; set; } - public Action ConfigureLayers { get; set; } + public Action ConfigureLayers { get; set; } public IEnumerable Versions { get; set; } = [NoxVersions.v1_0]; public bool UseDynamicRequestBodyOperationFilter { get; set; } = true; @@ -35,7 +34,7 @@ public class ApiServiceOptions public static class ApiServiceBuilder { - public async static Task AddApiServices(this WebApplicationBuilder builder, + public async static Task AddApiServices(this IHostApplicationBuilder builder, Action configureOptions) { ApiServiceOptions options = new(); @@ -52,7 +51,7 @@ public async static Task AddApiServices(this WebApplicati } var configuration = builder.Configuration; - NoxLogger logger = builder.SetUpLogger(); + NoxLogger logger = builder.SetUpLogger(); if (options.UseConsulKV) { @@ -65,7 +64,7 @@ await builder.AddConsulConfiguration(configuration["Consul:ServiceName"] builder.ConfigureServices(); logger.LogInformation($"-{serviceName}- Services configured...", false); - options.ConfigureLayers?.Invoke(builder.Services, logger, configuration); + options.ConfigureLayers?.Invoke(logger, configuration); logger.LogInformation($"-{serviceName}- Layers configured...", false); builder.ConfigureSwagger(options); @@ -74,23 +73,56 @@ await builder.AddConsulConfiguration(configuration["Consul:ServiceName"] return builder; } - private static NoxLogger SetUpLogger(this WebApplicationBuilder builder) + private static NoxLogger SetUpLogger(this IHostApplicationBuilder builder) { - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(builder.Configuration) - .CreateLogger(); + string seqServerUrl = builder.Configuration.GetConnectionString("appynox-seq") ?? + throw new Exception("Seq connection string could not found."); + + var logger = Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(builder.Configuration) + .WriteTo.Seq(seqServerUrl) + // TODO below comes from this thread: https://stackoverflow.com/questions/78369387/how-to-wire-up-serilog-to-net-aspire + .WriteTo.OpenTelemetry(options => + { + options.Endpoint = builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]; + var headers = builder.Configuration["OTEL_EXPORTER_OTLP_HEADERS"]?.Split(',') ?? []; + foreach (var header in headers) + { + var (key, value) = header.Split('=') switch + { + [string k, string v] => (k, v), + var v => throw new Exception($"Invalid header format {v}") + }; + + options.Headers.Add(key, value); + } + options.ResourceAttributes.Add("service.name", "apiservice"); - builder.Host.UseSerilog(Log.Logger); + //To remove the duplicate issue, we can use the below code to get the key and value from the configuration + var (otelResourceAttribute, otelResourceAttributeValue) = builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]?.Split('=') switch + { + [string k, string v] => (k, v), + _ => throw new Exception($"Invalid header format {builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]}") + }; + + options.ResourceAttributes.Add(otelResourceAttribute, otelResourceAttributeValue); + + }) + .CreateLogger(); + builder.AddSeqEndpoint("seq"); + + builder.Logging.AddSerilog(logger); var loggerFactory = LoggerFactory.Create(builder => { builder.AddSerilog(Log.Logger); }); - var logger = loggerFactory.CreateLogger(); - return new(logger, $"{builder.Configuration["Consul:ServiceName"]}Host"); + + var ilogger = loggerFactory.CreateLogger(); + return new(ilogger, $"{builder.Configuration["Consul:ServiceName"]}Host"); } - private static void ConfigureServices(this WebApplicationBuilder builder) + private static void ConfigureServices(this IHostApplicationBuilder builder) { // Add services to the container. builder.Services.AddControllers().AddJsonOptions(options => @@ -117,7 +149,7 @@ private static void ConfigureServices(this WebApplicationBuilder builder) builder.ConfigureLocalization(); } - private static void ConfigureSwagger(this WebApplicationBuilder builder, ApiServiceOptions options) + private static void ConfigureSwagger(this IHostApplicationBuilder builder, ApiServiceOptions options) { var serviceName = builder.Configuration["Consul:ServiceName"]; builder.Services.AddSwaggerGen(opt => diff --git a/src/Services/.BaseService/AppyNox.Services.Base.API/AppyNox.Services.Base.API.csproj b/src/Services/.BaseService/AppyNox.Services.Base.API/AppyNox.Services.Base.API.csproj index 4d09d8b0..55c9c52c 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.API/AppyNox.Services.Base.API.csproj +++ b/src/Services/.BaseService/AppyNox.Services.Base.API/AppyNox.Services.Base.API.csproj @@ -25,6 +25,8 @@ + + @@ -32,6 +34,7 @@ + diff --git a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/AppyNox.Services.Base.Infrastructure.csproj b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/AppyNox.Services.Base.Infrastructure.csproj index 9b1d6a52..b9af5549 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/AppyNox.Services.Base.Infrastructure.csproj +++ b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/AppyNox.Services.Base.Infrastructure.csproj @@ -31,6 +31,8 @@ + + @@ -50,7 +52,6 @@ - @@ -58,7 +59,6 @@ - diff --git a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/HostApplicationBuilderExtensions.cs b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/HostApplicationBuilderExtensions.cs index 82990e02..a81ccaee 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/HostApplicationBuilderExtensions.cs +++ b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/HostApplicationBuilderExtensions.cs @@ -1,13 +1,8 @@ -using AppyNox.Services.Base.Application.Interfaces.Caches; -using AppyNox.Services.Base.Infrastructure.Configuration; -using AppyNox.Services.Base.Infrastructure.Exceptions.Base; -using AppyNox.Services.Base.Infrastructure.Services.CacheServices; +using AppyNox.Services.Base.Infrastructure.Exceptions.Base; using Consul; using MassTransit; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using StackExchange.Redis; using System.Net; using System.Text; using System.Text.Json; @@ -25,23 +20,6 @@ public static class HostApplicationBuilderExtensions #region [ Public Methods ] - public static void AddMassTransitWithRabbitMq(this IHostApplicationBuilder builder) - { - builder.Services.AddMassTransit(busConfigurator => - { - busConfigurator.UsingRabbitMq((context, configurator) => - { - configurator.Host(new Uri(builder.Configuration["MessageBroker:Host"]!), h => - { - h.Username(builder.Configuration["MessageBroker:Username"]!); - h.Password(builder.Configuration["MessageBroker:Password"]!); - }); - - configurator.ConfigureEndpoints(context); - }); - }); - } - /// /// Adds and loads configuration settings from Consul for a specified microservice. This method initializes a Consul /// client, uploads local configuration files (appsettings or ocelot) to the Consul KV store, and configures the application diff --git a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/ServiceProviderExtensions.cs b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/ServiceProviderExtensions.cs index 813b7d1f..ad4cd28b 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/ServiceProviderExtensions.cs +++ b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Extensions/ServiceProviderExtensions.cs @@ -22,7 +22,13 @@ public static void ApplyMigrations(this IServiceProvider serviceProv { using var scope = serviceProvider.CreateScope(); var _db = scope.ServiceProvider.GetRequiredService(); + var dbConnection = _db.Database.GetDbConnection(); + var connectionString = dbConnection.ConnectionString; + // Display the connection string and database name + Console.WriteLine($"Applying migrations for {typeof(TDbContext).Name}"); + Console.WriteLine($"Connection string: {connectionString}"); + Console.WriteLine($"Database: {dbConnection.Database}"); if (_db.Database.GetPendingMigrations().Any()) { _db.Database.Migrate(); diff --git a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/InfrastructureServiceBuilder.cs b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/InfrastructureServiceBuilder.cs index 87c59c28..70c8a182 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/InfrastructureServiceBuilder.cs +++ b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/InfrastructureServiceBuilder.cs @@ -5,7 +5,6 @@ using AppyNox.Services.Base.Core.Common; using AppyNox.Services.Base.Infrastructure.Authentication; using AppyNox.Services.Base.Infrastructure.BackgroundJobs; -using AppyNox.Services.Base.Infrastructure.Configuration; using AppyNox.Services.Base.Infrastructure.Data; using AppyNox.Services.Base.Infrastructure.Data.Interceptors; using AppyNox.Services.Base.Infrastructure.HostedServices; @@ -17,16 +16,15 @@ using MassTransit; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.IdentityModel.Tokens; using Quartz; -using Serilog; using StackExchange.Redis; using System.ComponentModel.DataAnnotations; +using System.Text; using ValidationResult = System.ComponentModel.DataAnnotations.ValidationResult; namespace AppyNox.Services.Base.Infrastructure; @@ -38,6 +36,8 @@ public class InfrastructureSetupOptions public string Assembly { get; set; } [Required] public IConfiguration Configuration { get; set; } + [Required] + public string AspireDb { get; set; } public bool UseOutBoxMessageMechanism { get; set; } = false; public int OutBoxMessageJobIntervalSeconds { get; set; } = 30; public bool UseEncryption { get; set; } = false; @@ -56,8 +56,8 @@ public class InfrastructureSetupOptions public static class InfrastructureServiceBuilder { - public static IServiceCollection AddInfrastructureServices( - this IServiceCollection services, + public static IHostApplicationBuilder AddInfrastructureServices( + this IHostApplicationBuilder builder, INoxLogger logger, Action configureOptions) where TContext : DbContext, INoxDatabaseContext { @@ -73,6 +73,7 @@ public static IServiceCollection AddInfrastructureServices( var errors = string.Join(", ", validationResults.Select(vr => vr.ErrorMessage)); throw new InvalidOperationException($"Invalid options: {errors}"); } + IServiceCollection services = builder.Services; services.AddSingleton(typeof(INoxApplicationLogger<>), typeof(NoxApplicationLogger<>)); services.AddSingleton(typeof(INoxInfrastructureLogger<>), typeof(NoxInfrastructureLogger<>)); @@ -85,7 +86,7 @@ public static IServiceCollection AddInfrastructureServices( logger.LogInformation($"-{serviceName}- Consul enabled...", false); } - services.ConfigureDatabase(options); + builder.ConfigureDatabase(options); logger.LogInformation($"-{serviceName}- Database connection enabled...", false); if (options.UseEncryption) @@ -102,7 +103,7 @@ public static IServiceCollection AddInfrastructureServices( if (options.UseRedis) { - services.ConfigureRedis(options.Configuration); + builder.ConfigureRedis(); logger.LogInformation($"-{serviceName}- Redis enabled...", false); } @@ -118,7 +119,7 @@ public static IServiceCollection AddInfrastructureServices( } logger.LogInformation($"-{serviceName}- Finished Adding Infrastructure Services, finalizing...", false); - return services; + return builder; } #region [ Builders ] @@ -137,35 +138,37 @@ private static IServiceCollection ConfigureConsulServices(this IServiceCollectio return services; } - private static IServiceCollection ConfigureDatabase(this IServiceCollection services, InfrastructureSetupOptions options) + private static IHostApplicationBuilder ConfigureDatabase(this IHostApplicationBuilder builder, InfrastructureSetupOptions options) where TContext : DbContext, INoxDatabaseContext { - string? connectionString = options.Configuration.GetConnectionString("DefaultConnection"); - if (options.UseOutBoxMessageMechanism) { - services.AddSingleton(); + builder.Services.AddSingleton(); } - services.AddDbContext((sp, opt) => + builder.AddNpgsqlDbContext( + options.AspireDb, + configureDbContextOptions: opt => { - opt.UseNpgsql(connectionString, sqlOptions => + opt.UseNpgsql(npgsqlOptions => { - sqlOptions.MigrationsAssembly(options.Assembly); + opt.UseLazyLoadingProxies(); + npgsqlOptions.MigrationsAssembly(options.Assembly); + if (options.UseOutBoxMessageMechanism) { - ConvertDomainEventsToOutboxMessagesInterceptor outboxMessageInterceptor = sp.GetService() + var outboxMessageInterceptor = builder.Services.BuildServiceProvider() + .GetService() ?? throw new ArgumentException("ConvertDomainEventsToOutboxMessagesInterceptor was null!"); - opt.UseNpgsql(connectionString).AddInterceptors(outboxMessageInterceptor); - } - else - { - opt.UseNpgsql(connectionString); + opt.AddInterceptors(outboxMessageInterceptor); } }); }); - return services; + + builder.EnrichNpgsqlDbContext(); + + return builder; } private static IServiceCollection ConfigureOutBoxMessageJob(this IServiceCollection services, InfrastructureSetupOptions options) @@ -184,17 +187,11 @@ private static IServiceCollection ConfigureOutBoxMessageJob(this IServ return services; } - private static IServiceCollection ConfigureRedis(this IServiceCollection services, IConfiguration configuration) + private static IServiceCollection ConfigureRedis(this IHostApplicationBuilder builder) { - RedisConfiguration? redisConfig = configuration.GetSection("Redis").Get(); - if (redisConfig == null || string.IsNullOrWhiteSpace(redisConfig.ConnectionString)) - { - throw new InvalidOperationException("Redis configuration is missing or invalid."); - } - - services.AddSingleton(ConnectionMultiplexer.Connect(redisConfig.ConnectionString)); - services.AddSingleton(); - return services; + builder.AddRedisClient("appynox-cache"); + builder.Services.AddSingleton(); + return builder.Services; } private static IServiceCollection AddJwtAuthentication(this IServiceCollection services, string serviceName, InfrastructureSetupOptions options, INoxLogger logger) @@ -227,14 +224,6 @@ private static IServiceCollection AddJwtAuthentication(this IServiceCollection s private static IServiceCollection AddMassTransit(this IServiceCollection services, string serviceName, InfrastructureSetupOptions options, INoxLogger logger) { - string hostUrl = options.Configuration["MessageBroker:Host"] - ?? throw new InvalidOperationException("MessageBroker:Host is not defined!"); - - string username = options.Configuration["MessageBroker:Username"] - ?? throw new InvalidOperationException("MessageBroker:Username is not defined!"); - string password = options.Configuration["MessageBroker:Password"] - ?? throw new InvalidOperationException("MessageBroker:Password is not defined!"); - services.AddMassTransit(busConfigurator => { options.MassTransitConfiguration?.Invoke(busConfigurator); @@ -253,14 +242,9 @@ private static IServiceCollection AddMassTransit(this IServiceCollection service configurator.UseConsumeFilter(typeof(NoxContextConsumeFilter<>), context); - configurator.Host( - new Uri(hostUrl), - h => - { - h.Username(username); - h.Password(password); - } - ); + var configService = context.GetRequiredService(); + var connectionString = configService.GetConnectionString("appynox-rabbitmq"); + configurator.Host(connectionString); options.RabbitMqConfiguration?.Invoke((context, configurator)); diff --git a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Services/CacheServices/RedisCacheService.cs b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Services/CacheServices/RedisCacheService.cs index 3000ae1c..3d86ba7d 100644 --- a/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Services/CacheServices/RedisCacheService.cs +++ b/src/Services/.BaseService/AppyNox.Services.Base.Infrastructure/Services/CacheServices/RedisCacheService.cs @@ -3,20 +3,11 @@ namespace AppyNox.Services.Base.Infrastructure.Services.CacheServices; -public class RedisCacheService : ICacheService +public class RedisCacheService(IConnectionMultiplexer redis) : ICacheService { #region [ Fields ] - private readonly IConnectionMultiplexer _redis; - - #endregion - - #region [ Public Constructors ] - - public RedisCacheService(IConnectionMultiplexer redis) - { - _redis = redis; - } + private readonly IConnectionMultiplexer _redis = redis; #endregion diff --git a/src/Services/.BaseService/Tests/IntegrationTests/AppyNox.Services.Base.IntegrationTests/AppyNox.Services.Base.IntegrationTests.csproj b/src/Services/.BaseService/Tests/IntegrationTests/AppyNox.Services.Base.IntegrationTests/AppyNox.Services.Base.IntegrationTests.csproj index ed26ce42..ceffbc4f 100644 --- a/src/Services/.BaseService/Tests/IntegrationTests/AppyNox.Services.Base.IntegrationTests/AppyNox.Services.Base.IntegrationTests.csproj +++ b/src/Services/.BaseService/Tests/IntegrationTests/AppyNox.Services.Base.IntegrationTests/AppyNox.Services.Base.IntegrationTests.csproj @@ -23,8 +23,6 @@ - - diff --git a/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/CQRSFixtures/NoxApplicationTestFixture.cs b/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/CQRSFixtures/NoxApplicationTestFixture.cs index d2510219..1257b807 100644 --- a/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/CQRSFixtures/NoxApplicationTestFixture.cs +++ b/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/CQRSFixtures/NoxApplicationTestFixture.cs @@ -5,6 +5,7 @@ using AppyNox.Services.Base.Application.UnitTests.Stubs; using AppyNox.Services.Base.Core.Enums; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Localization; using Moq; @@ -20,6 +21,8 @@ public class NoxApplicationTestFixture : IDisposable public readonly IServiceCollection ServiceCollection; + public readonly StubHostApplicationBuilder Builder; + public readonly Mock MockQueryParameters; public bool DIInitialized { get; set; } = false; @@ -30,7 +33,8 @@ public class NoxApplicationTestFixture : IDisposable public NoxApplicationTestFixture() { - ServiceCollection = new ServiceCollection(); + Builder = new(); + ServiceCollection = Builder.Services; ServiceCollection.AddScoped(typeof(INoxApplicationLogger<>), typeof(NoxApplicationLoggerStub<>)); _unitOfWork = new(); diff --git a/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/StubHostApplicationBuilder.cs b/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/StubHostApplicationBuilder.cs new file mode 100644 index 00000000..9083f4fc --- /dev/null +++ b/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Application.UnitTests/StubHostApplicationBuilder.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.Metrics; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace AppyNox.Services.Base.Application.UnitTests; + +public class StubHostApplicationBuilder : IHostApplicationBuilder +{ + public IServiceCollection Services { get; } = new ServiceCollection(); + + public IConfigurationManager Configuration => throw new NotImplementedException(); + + public IHostEnvironment Environment => throw new NotImplementedException(); + + public ILoggingBuilder Logging => throw new NotImplementedException(); + + public IMetricsBuilder Metrics => throw new NotImplementedException(); + + IDictionary IHostApplicationBuilder.Properties => throw new NotImplementedException(); + + public void ConfigureContainer(IServiceProviderFactory factory, Action? configure = null) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } +} diff --git a/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Infrastructure.UnitTests/Fixtures/RepositoryFixture.cs b/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Infrastructure.UnitTests/Fixtures/RepositoryFixture.cs index 81862b07..b255b0be 100644 --- a/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Infrastructure.UnitTests/Fixtures/RepositoryFixture.cs +++ b/src/Services/.BaseService/Tests/UnitTests/AppyNox.Services.Base.Infrastructure.UnitTests/Fixtures/RepositoryFixture.cs @@ -44,6 +44,7 @@ public static TContext CreateDatabaseContext() where TContext : DbCont var databaseName = Guid.NewGuid().ToString(); // Unique database name var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName) + .UseLazyLoadingProxies() .Options; // Using Activator to create an instance of TContext diff --git a/src/Services/CouponService/AppyNox.Services.Coupon.Application/DependencyInjection.cs b/src/Services/CouponService/AppyNox.Services.Coupon.Application/DependencyInjection.cs index ddc29ba6..ca197ed8 100644 --- a/src/Services/CouponService/AppyNox.Services.Coupon.Application/DependencyInjection.cs +++ b/src/Services/CouponService/AppyNox.Services.Coupon.Application/DependencyInjection.cs @@ -6,6 +6,7 @@ using AppyNox.Services.Coupon.Domain.Entities; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using System.Reflection; namespace AppyNox.Services.Coupon.Application; @@ -14,8 +15,9 @@ public static class DependencyInjection { #region [ Public Methods ] - public static IServiceCollection AddCouponApplication(this IServiceCollection services, IConfiguration configuration, INoxLogger logger) + public static IHostApplicationBuilder AddCouponApplication(this IHostApplicationBuilder builder, IConfiguration configuration, INoxLogger logger) { + IServiceCollection services = builder.Services; services.AddApplicationServices(logger, options => { options.Assembly = Assembly.GetExecutingAssembly().GetName().Name; @@ -30,7 +32,7 @@ public static IServiceCollection AddCouponApplication(this IServiceCollection se services.AddNoxEntityCommands(); services.AddAnemicEntityCommands(); - return services; + return builder; } #endregion diff --git a/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/Data/CouponDbContext.cs b/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/Data/CouponDbContext.cs index 281df5f5..7c68d30b 100644 --- a/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/Data/CouponDbContext.cs +++ b/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/Data/CouponDbContext.cs @@ -34,13 +34,6 @@ public class CouponDbContext(DbContextOptions options, IEncrypt #region [ Protected Methods ] - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - optionsBuilder - .UseLazyLoadingProxies(); - } - protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); diff --git a/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/DependencyInjection.cs b/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/DependencyInjection.cs index 17386b2b..dfc77b75 100644 --- a/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/DependencyInjection.cs +++ b/src/Services/CouponService/AppyNox.Services.Coupon.Infrastructure/DependencyInjection.cs @@ -1,16 +1,16 @@ using AppyNox.Services.Base.Application.Interfaces.Loggers; using AppyNox.Services.Base.Application.Interfaces.Repositories; using AppyNox.Services.Base.Infrastructure; -using AppyNox.Services.Base.Infrastructure.Authentication; using AppyNox.Services.Coupon.Application.Permission; using AppyNox.Services.Coupon.Infrastructure.Authentication; using AppyNox.Services.Coupon.Infrastructure.Data; using AppyNox.Services.Coupon.Infrastructure.Repositories; using AppyNox.Services.License.Client; using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Reflection; namespace AppyNox.Services.Coupon.Infrastructure; @@ -21,15 +21,17 @@ public static class DependencyInjection /// /// Centralized Dependency Injection For Infrastructure Layer. /// - /// + /// /// /// /// - public static IServiceCollection AddCouponInfrastructure(this IServiceCollection services, IConfiguration configuration, INoxLogger logger) + public static IHostApplicationBuilder AddCouponInfrastructure(this IHostApplicationBuilder builder, IConfiguration configuration, INoxLogger logger) { - services.AddInfrastructureServices(logger, options => + IServiceCollection services = builder.Services; + builder.AddInfrastructureServices(logger, options => { - options.Assembly = "AppyNox.Services.Coupon.Infrastructure"; + options.Assembly = Assembly.GetExecutingAssembly().GetName().Name; + options.AspireDb = "appynox-coupon-db"; options.UseOutBoxMessageMechanism = true; options.OutBoxMessageJobIntervalSeconds = 10; options.UseEncryption = true; @@ -76,7 +78,7 @@ public static IServiceCollection AddCouponInfrastructure(this IServiceCollection services.AddScoped(); logger.LogInformation("Registered Fleet JWT Configuration.", false); - return services; + return builder; } #endregion diff --git a/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/Program.cs b/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/Program.cs index e890b0b3..40505b2f 100644 --- a/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/Program.cs +++ b/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/Program.cs @@ -11,9 +11,9 @@ await builder.AddApiServices(options => { options.SetupHostName = "CouponHost"; options.UseConsulKV = true; - options.ConfigureLayers = (services, logger, configuration) => + options.ConfigureLayers = (logger, configuration) => { - services + builder .AddCouponApplication(configuration, logger) .AddCouponInfrastructure(configuration, logger); }; diff --git a/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.Development.json b/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.Development.json index 016892a7..2fabdff3 100644 --- a/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.Development.json +++ b/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.Development.json @@ -9,22 +9,13 @@ } }, "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Seq", - "Args": { - "serverUrl": "http://localhost:5341" - } - } + { "Name": "Console" } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithProperty" ], "Properties": { "Service": "CouponService" } }, - "ConnectionStrings": { - "DefaultConnection": "User ID=postgres;Password=sapass;Server=localhost;Port=5432;Database=AppyNox_Coupon;Pooling=true" - }, "JwtSettings": { "Sso": { "SecretKey": "XPFk7n/yI+Sm9DtWlZ/6TYawZs22meQjENPNMmZ9ONA=", @@ -52,16 +43,8 @@ "HealthCheckIntervalSeconds": 30, "HealthCheckTimeoutSeconds": 5 }, - "Redis": { - "ConnectionString": "localhost:6379" - }, "Encryption": { "Key": "Xj7xynADC4/fLF/R30B5IvAWDcmawemI+Ng+p96P5Vs=", "IV": "wuiFPQA3L3G1qOt8Y5BkhQ==" - }, - "MessageBroker": { - "Host": "rabbitmq://localhost", - "Username": "guest", - "Password": "guest" } } \ No newline at end of file diff --git a/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.json b/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.json index 63aaee8b..68f8e4be 100644 --- a/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.json +++ b/src/Services/CouponService/AppyNox.Services.Coupon.WebAPI/appsettings.json @@ -9,22 +9,13 @@ } }, "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Seq", - "Args": { - "serverUrl": "" - } - } + { "Name": "Console" } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithProperty" ], "Properties": { "Service": "CouponService" } }, - "ConnectionStrings": { - "DefaultConnection": "" - }, "JwtSettings": { "Sso": { "SecretKey": "", @@ -51,16 +42,8 @@ "HealthCheckIntervalSeconds": 30, "HealthCheckTimeoutSeconds": 5 }, - "Redis": { - "ConnectionString": "" - }, "Encryption": { "Key": "", "IV": "" - }, - "MessageBroker": { - "Host": "", - "Username": "", - "Password": "" } } \ No newline at end of file diff --git a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/AppyNox.Services.Coupon.Benchmark.csproj b/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/AppyNox.Services.Coupon.Benchmark.csproj deleted file mode 100644 index 2fb376a5..00000000 --- a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/AppyNox.Services.Coupon.Benchmark.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - - - PreserveNewest - - - PreserveNewest - appsettings.json - - - - - - - - - - - - - - diff --git a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/DependencyInjection.cs b/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/DependencyInjection.cs deleted file mode 100644 index 23891c68..00000000 --- a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/DependencyInjection.cs +++ /dev/null @@ -1,54 +0,0 @@ -using AppyNox.Services.Base.Application.Interfaces.Loggers; -using AppyNox.Services.Base.Core.Enums; -using AppyNox.Services.Base.Infrastructure.Services.LoggerService; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Serilog; -using AppyNox.Services.Coupon.Infrastructure; -using AppyNox.Services.Base.Application.Interfaces.Caches; -using AppyNox.Services.Base.Infrastructure.Services.CacheServices; -using StackExchange.Redis; -using AppyNox.Services.Base.Infrastructure.Configuration; -using Microsoft.AspNetCore.Builder; - -namespace AppyNox.Services.Coupon.Benchmark; - -internal static class DependencyInjection -{ - internal static void AddInfrastructureBenchmark(this IServiceCollection serviceCollection) - { - var configuration = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.Development.json", optional: true) - .AddEnvironmentVariables() - .Build(); - - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration) - .CreateLogger(); - - var loggerFactory = LoggerFactory.Create(builder => - { - builder.AddSerilog(); - }); - var logger = loggerFactory.CreateLogger(); - NoxLogger noxLogger = new(logger, "CouponBenchmark"); - - serviceCollection.AddLogging(builder => - builder.AddConsole() - .AddDebug()); - - RedisConfiguration? redisConfig = configuration.GetSection("Redis").Get(); - if (redisConfig == null || string.IsNullOrWhiteSpace(redisConfig.ConnectionString)) - { - throw new InvalidOperationException("Redis configuration is missing or invalid."); - } - - serviceCollection.AddSingleton(ConnectionMultiplexer.Connect(redisConfig.ConnectionString)); - serviceCollection.AddSingleton(); - - serviceCollection.AddCouponInfrastructure(configuration, noxLogger); - } -} \ No newline at end of file diff --git a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/Program.cs b/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/Program.cs deleted file mode 100644 index b539ebfd..00000000 --- a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/Program.cs +++ /dev/null @@ -1,8 +0,0 @@ -using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Running; - -var logger = new BenchmarkDotNet.Loggers.ConsoleLogger(); -var config = ManualConfig.Create(DefaultConfig.Instance) - .AddLogger(logger); - -BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config); \ No newline at end of file diff --git a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/RepositoryBenchmarks/NoxRepositoryBenchmark.cs b/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/RepositoryBenchmarks/NoxRepositoryBenchmark.cs deleted file mode 100644 index 04854a3c..00000000 --- a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/RepositoryBenchmarks/NoxRepositoryBenchmark.cs +++ /dev/null @@ -1,157 +0,0 @@ -using AppyNox.Services.Base.Application.Interfaces.Caches; -using AppyNox.Services.Base.Application.Interfaces.Repositories; -using AppyNox.Services.Base.Infrastructure.Repositories.Common; -using AppyNox.Services.Coupon.Infrastructure.Repositories; -using BenchmarkDotNet.Attributes; -using Microsoft.Extensions.DependencyInjection; -using CouponRoot = AppyNox.Services.Coupon.Domain.Coupons.Coupon; - -namespace AppyNox.Services.Coupon.Benchmark.RepositoryBenchmarks; - -[MemoryDiagnoser] -public class NoxRepositoryBenchmark -{ - private IServiceProvider ServiceProvider = default!; - - [GlobalSetup] - public void Setup() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddInfrastructureBenchmark(); - ServiceProvider = serviceCollection.BuildServiceProvider(); - } - - [Benchmark] - public async Task NoxGetAllAsyncPlainSimpleBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters(); - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task NoxGetAllAsyncPlainBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters(); - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task CouponGetAllAsyncPlainBenchmark() - { - ICouponRepository couponRepository = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters(); - await couponRepository.GetAllEfCoreAsync(queryParameters); - } - - [Benchmark] - public async Task NoxGetAllAsyncWithSortSimpleBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - SortBy = "Id desc, CouponDetail.detail desc" - }; - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task NoxGetAllAsyncWithSortBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - SortBy = "Id desc, CouponDetail.detail desc" - }; - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task CouponGetAllAsyncWithSortBenchmark() - { - ICouponRepository couponRepository = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - SortBy = "Id desc, CouponDetail.detail desc" - }; - await couponRepository.GetAllEfCoreAsync(queryParameters); - } - - [Benchmark] - public async Task NoxGetAllAsyncWithFilterSimpleBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - Filter = "Amount.minAmount == 100 and (detail == \"Detail2\" || detail.Contains(\"2\"))" - }; - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task NoxGetAllAsyncWithFilterBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - Filter = "Amount.minAmount == 100 and (detail == \"Detail2\" || detail.Contains(\"2\"))" - }; - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task CouponGetAllAsyncWithFilterBenchmark() - { - ICouponRepository couponRepository = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - Filter = "Amount.minAmount == 100 and (detail == \"Detail2\" || detail.Contains(\"2\"))" - }; - await couponRepository.GetAllEfCoreAsync(queryParameters); - } - - [Benchmark] - public async Task NoxGetAllAsyncWithSortAndFilterSimpleBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - SortBy = "Id desc, CouponDetail.detail desc", - Filter = "Amount.minAmount == 100 and (detail == \"Detail2\" || detail.Contains(\"2\"))" - }; - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task NoxGetAllAsyncWithSortAndFilterBenchmark() - { - INoxRepository noxRepository = ServiceProvider.GetRequiredService>(); - ICacheService cacheService = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - SortBy = "Id desc, CouponDetail.detail desc", - Filter = "Amount.minAmount == 100 and (detail == \"Detail2\" || detail.Contains(\"2\"))" - }; - await noxRepository.GetAllAsync(queryParameters, cacheService); - } - - [Benchmark] - public async Task CouponGetAllAsyncWithSortAndFilterBenchmark() - { - ICouponRepository couponRepository = ServiceProvider.GetRequiredService(); - IQueryParameters queryParameters = new QueryParameters - { - SortBy = "Id desc, CouponDetail.detail desc", - Filter = "Amount.minAmount == 100 and (detail == \"Detail2\" || detail.Contains(\"2\"))" - }; - await couponRepository.GetAllEfCoreAsync(queryParameters); - } -} \ No newline at end of file diff --git a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/appsettings.json b/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/appsettings.json deleted file mode 100644 index 33f01455..00000000 --- a/src/Services/CouponService/Tests/Benchmarks/AppyNox.Services.Coupon.Benchmark/appsettings.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "Serilog": { - "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Debug" ], - "MinimumLevel": { - "Default": "Debug", - "Override": { - "Microsoft": "Information", - "System": "Information" - } - }, - "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Debug", - "Args": { "restrictedToMinimumLevel": "Debug" } - } - ], - "Enrich": [ "FromLogContext" ] - }, - "ConnectionStrings": { - "DevelopmentConnection": "", - "StagingConnection": "", - "ProductionConnection": "", - "DefaultConnection": "", - "TestConnection": "" // for integration tests, use this to connect to dockerized database container from localhost - }, - "ConsulConfiguration": { - "Address": "{Consul HOST}" - }, - "Consul": { - "ServiceId": "{}", - "ServiceName": "{}", - "Scheme": "{http or https}", - "ServiceHost": "{}", - "ServicePort": "PORT", - "Tags": [ "Tag1", "Tag2" ], - "HealthCheckUrl": "{health-check-url}", - "HealthCheckIntervalSeconds": 30, - "HealthCheckTimeoutSeconds": 5 - }, - "Redis": { - "ConnectionString": "localhost:6379" - } -} \ No newline at end of file diff --git a/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/CouponDddCQRSUnitTest.cs b/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/CouponDddCQRSUnitTest.cs index db1ba7d3..a2acc38b 100644 --- a/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/CouponDddCQRSUnitTest.cs +++ b/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/CouponDddCQRSUnitTest.cs @@ -55,7 +55,7 @@ public CouponDddCQRSUnitTest(NoxApplicationTestFixture fixture) .AddInMemoryCollection(inMemorySettings!) .Build(); - _fixture.ServiceCollection.AddCouponApplication(configuration, logger); + _fixture.Builder.AddCouponApplication(configuration, logger); _fixture.ServiceCollection.AddScoped(typeof(INoxRepository), _ => mockRepository.Object); _fixture.DIInitialized = true; } diff --git a/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/TicketAnemicCQRSUnitTest.cs b/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/TicketAnemicCQRSUnitTest.cs index 2d409b30..9552d33c 100644 --- a/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/TicketAnemicCQRSUnitTest.cs +++ b/src/Services/CouponService/Tests/UnitTests/AppyNox.Services.Coupon.Application.UnitTest/CQRSTests/TicketAnemicCQRSUnitTest.cs @@ -49,7 +49,7 @@ public TicketAnemicCQRSUnitTest(NoxApplicationTestFixture fixture) .AddInMemoryCollection(inMemorySettings!) .Build(); - _fixture.ServiceCollection.AddCouponApplication(configuration, logger); + _fixture.Builder.AddCouponApplication(configuration, logger); _fixture.ServiceCollection.AddScoped(typeof(IGenericRepository), _ => mockRepository.Object); _fixture.DIInitialized = true; } diff --git a/src/Services/LicenseService/AppyNox.Services.License.Application/DependencyInjection.cs b/src/Services/LicenseService/AppyNox.Services.License.Application/DependencyInjection.cs index 416fb248..f8d61d31 100644 --- a/src/Services/LicenseService/AppyNox.Services.License.Application/DependencyInjection.cs +++ b/src/Services/LicenseService/AppyNox.Services.License.Application/DependencyInjection.cs @@ -1,12 +1,11 @@ using AppyNox.Services.Base.Application; -using AppyNox.Services.Base.Application.DtoUtilities; using AppyNox.Services.Base.Application.Extensions; using AppyNox.Services.Base.Application.Interfaces.Loggers; using AppyNox.Services.License.Application.Dtos.DtoUtilities; using AppyNox.Services.License.Domain.Entities; -using FluentValidation; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using System.Reflection; namespace AppyNox.Services.License.Application @@ -15,8 +14,9 @@ public static class DependencyInjection { #region [ Public Methods ] - public static IServiceCollection AddLicenseApplication(this IServiceCollection services, IConfiguration configuration, INoxLogger logger) + public static IHostApplicationBuilder AddLicenseApplication(this IHostApplicationBuilder builder, IConfiguration configuration, INoxLogger logger) { + IServiceCollection services = builder.Services; services.AddApplicationServices(logger, options => { options.Assembly = Assembly.GetExecutingAssembly().GetName().Name; @@ -31,7 +31,7 @@ public static IServiceCollection AddLicenseApplication(this IServiceCollection s services.AddNoxEntityCommands(); services.AddNoxEntityCommands(); - return services; + return builder; } #endregion diff --git a/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/Data/LicenseDatabaseContext.cs b/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/Data/LicenseDatabaseContext.cs index a51ccebf..c5be2bd2 100644 --- a/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/Data/LicenseDatabaseContext.cs +++ b/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/Data/LicenseDatabaseContext.cs @@ -28,13 +28,6 @@ public class LicenseDatabaseContext(DbContextOptions opt #region [ Protected Methods ] - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - - //optionsBuilder.UseNpgsql("User ID=postgres;Password=sapass;Server=localhost;Port=5432;Database=AppyNox_License;Pooling=true"); - } - protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); diff --git a/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/DependencyInjection.cs b/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/DependencyInjection.cs index 1f242eb3..dcad1a78 100644 --- a/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/DependencyInjection.cs +++ b/src/Services/LicenseService/AppyNox.Services.License.Infrastructure/DependencyInjection.cs @@ -9,6 +9,7 @@ using MassTransit; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using System.Reflection; namespace AppyNox.Services.License.Infrastructure @@ -17,11 +18,13 @@ public static class DependencyInjection { #region [ Public Methods ] - public static IServiceCollection AddLicenseInfrastructure(this IServiceCollection services, IConfiguration configuration, INoxLogger logger) + public static IHostApplicationBuilder AddLicenseInfrastructure(this IHostApplicationBuilder builder, IConfiguration configuration, INoxLogger logger) { - services.AddInfrastructureServices(logger, options => + IServiceCollection services = builder.Services; + builder.AddInfrastructureServices(logger, options => { options.Assembly = Assembly.GetExecutingAssembly().GetName().Name; + options.AspireDb = "appynox-license-db"; options.UseOutBoxMessageMechanism = true; options.OutBoxMessageJobIntervalSeconds = 10; options.UseConsul = true; @@ -67,7 +70,7 @@ public static IServiceCollection AddLicenseInfrastructure(this IServiceCollectio services.AddScoped(); services.AddScoped(); - return services; + return builder; } #endregion diff --git a/src/Services/LicenseService/AppyNox.Services.License.WebAPI/Program.cs b/src/Services/LicenseService/AppyNox.Services.License.WebAPI/Program.cs index 3053f4f8..d913444a 100644 --- a/src/Services/LicenseService/AppyNox.Services.License.WebAPI/Program.cs +++ b/src/Services/LicenseService/AppyNox.Services.License.WebAPI/Program.cs @@ -10,9 +10,9 @@ await builder.AddApiServices(options => { options.SetupHostName = "CouponHost"; options.UseConsulKV = true; - options.ConfigureLayers = (services, logger, configuration) => + options.ConfigureLayers = (logger, configuration) => { - services + builder .AddLicenseApplication(configuration, logger) .AddLicenseInfrastructure(configuration, logger); }; diff --git a/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.Development.json b/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.Development.json index abab281f..44c8d53e 100644 --- a/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.Development.json +++ b/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.Development.json @@ -9,22 +9,13 @@ } }, "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Seq", - "Args": { - "serverUrl": "http://localhost:5341" - } - } + { "Name": "Console" } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithProperty" ], "Properties": { "Service": "LicenseService" } }, - "ConnectionStrings": { - "DefaultConnection": "User ID=postgres;Password=sapass;Server=localhost;Port=5432;Database=AppyNox_License;Pooling=true" - }, "JwtSettings": { "SecretKey": "XPFk7n/yI+Sm9DtWlZ/6TYawZs22meQjENPNMmZ9ONA=", "Issuer": "NoxAuthServer", @@ -44,13 +35,5 @@ "HealthCheckUrl": "api/health", "HealthCheckIntervalSeconds": 30, "HealthCheckTimeoutSeconds": 5 - }, - "MessageBroker": { - "Host": "rabbitmq://localhost", - "Username": "guest", - "Password": "guest" - }, - "Redis": { - "ConnectionString": "localhost:6379" } } \ No newline at end of file diff --git a/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.json b/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.json index 0ed0b69e..d8d84682 100644 --- a/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.json +++ b/src/Services/LicenseService/AppyNox.Services.License.WebAPI/appsettings.json @@ -9,22 +9,13 @@ } }, "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Seq", - "Args": { - "serverUrl": "" - } - } + { "Name": "Console" } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithProperty" ], "Properties": { "Service": "LicenseService" } }, - "ConnectionStrings": { - "DefaultConnection": "" - }, "JwtSettings": { "SecretKey": "", "Issuer": "NoxAuthServer", @@ -43,13 +34,5 @@ "HealthCheckUrl": "", "HealthCheckIntervalSeconds": 30, "HealthCheckTimeoutSeconds": 5 - }, - "MessageBroker": { - "Host": "", - "Username": "", - "Password": "" - }, - "Redis": { - "ConnectionString": "" } } \ No newline at end of file diff --git a/src/Services/LicenseService/Tests/UnitTests/AppyNox.Services.License.Application.UnitTest/CQRSTests/LicenseCQRSUnitTests.cs b/src/Services/LicenseService/Tests/UnitTests/AppyNox.Services.License.Application.UnitTest/CQRSTests/LicenseCQRSUnitTests.cs index 2f3404e5..4e1d4f2d 100644 --- a/src/Services/LicenseService/Tests/UnitTests/AppyNox.Services.License.Application.UnitTest/CQRSTests/LicenseCQRSUnitTests.cs +++ b/src/Services/LicenseService/Tests/UnitTests/AppyNox.Services.License.Application.UnitTest/CQRSTests/LicenseCQRSUnitTests.cs @@ -48,7 +48,7 @@ public LicenseCQRSUnitTests(NoxApplicationTestFixture fixture) IConfiguration configuration = new ConfigurationBuilder() .AddInMemoryCollection(inMemorySettings!) .Build(); - _fixture.ServiceCollection.AddLicenseApplication(configuration, logger); + _fixture.Builder.AddLicenseApplication(configuration, logger); _fixture.ServiceCollection.AddScoped(typeof(INoxRepository), _ => mockRepository.Object); _fixture.DIInitialized = true; } diff --git a/src/Services/SsoService/AppyNox.Services.Sso.Application/DependencyInjection.cs b/src/Services/SsoService/AppyNox.Services.Sso.Application/DependencyInjection.cs index f51829a0..45966318 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.Application/DependencyInjection.cs +++ b/src/Services/SsoService/AppyNox.Services.Sso.Application/DependencyInjection.cs @@ -1,10 +1,8 @@ using AppyNox.Services.Base.Application; -using AppyNox.Services.Base.Application.DtoUtilities; using AppyNox.Services.Base.Application.Interfaces.Loggers; -using FluentValidation; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Hosting; using System.Reflection; namespace AppyNox.Services.Sso.Application @@ -19,14 +17,15 @@ public static class DependencyInjection /// /// Adds Sso services and AutoMapper configurations to the specified IServiceCollection. /// - /// The IServiceCollection to add services to. + /// The IServiceCollection to add services to. /// The IConfiguration instance to access application settings. - public static IServiceCollection AddSsoApplication( - this IServiceCollection services, + public static IHostApplicationBuilder AddSsoApplication( + this IHostApplicationBuilder builder, IConfiguration configuration, INoxLogger logger ) { + IServiceCollection services = builder.Services; services.AddApplicationServices(logger, options => { options.Assembly = Assembly.GetExecutingAssembly().GetName().Name; @@ -37,7 +36,7 @@ INoxLogger logger options.UseMediatR = true; }); - return services; + return builder; } #endregion diff --git a/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/Data/IdentityDatabaseContext.cs b/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/Data/IdentityDatabaseContext.cs index 94f4302d..ff6d4659 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/Data/IdentityDatabaseContext.cs +++ b/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/Data/IdentityDatabaseContext.cs @@ -34,6 +34,7 @@ public class IdentityDatabaseContext(DbContextOptions o { private readonly IEncryptionService? _encryptionService = encryptionService; + #region [ Properties ] public DbSet Companies { get; set; } diff --git a/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/DependencyInjection.cs b/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/DependencyInjection.cs index 25c88fad..29601081 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/DependencyInjection.cs +++ b/src/Services/SsoService/AppyNox.Services.Sso.Infrastructure/DependencyInjection.cs @@ -22,6 +22,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; using System.Reflection; @@ -38,16 +39,20 @@ public static class DependencyInjection /// Adds sso infrastructure services. /// /// The IConfiguration instance to access application settings. - public static IServiceCollection AddSsoInfrastructure( - this IServiceCollection services, + public static IHostApplicationBuilder AddSsoInfrastructure( + this IHostApplicationBuilder builder, IConfiguration configuration, INoxLogger noxLogger, bool isWeb = false ) { - services.AddInfrastructureServices(noxLogger, options => + IServiceCollection services = builder.Services; + builder.AddNpgsqlDbContext("appynox-sso-saga-db"); // Register saga db first, we will call ExistingDbContext for MassTransit + + builder.AddInfrastructureServices(noxLogger, options => { options.Assembly = Assembly.GetExecutingAssembly().GetName().Name; + options.AspireDb = "appynox-sso-db"; options.UseOutBoxMessageMechanism = true; options.OutBoxMessageJobIntervalSeconds = 10; options.UseEncryption = false; @@ -79,14 +84,7 @@ public static IServiceCollection AddSsoInfrastructure( .EntityFrameworkRepository(r => { r.ConcurrencyMode = ConcurrencyMode.Pessimistic; - r.AddDbContext( - (provider, builder) => - { - builder.UseNpgsql( - configuration.GetConnectionString("SagaConnection") - ); - } - ); + r.ExistingDbContext(); r.UsePostgres(); }); @@ -144,14 +142,9 @@ public static IServiceCollection AddSsoInfrastructure( busConfigurator.UsingRabbitMq( (context, configurator) => { - configurator.Host( - new Uri(configuration["NoxMessageBroker:Host"]!), - h => - { - h.Username(configuration["NoxMessageBroker:Username"]!); - h.Password(configuration["NoxMessageBroker:Password"]!); - } - ); + var configService = context.GetRequiredService(); + var connectionString = configService.GetConnectionString("external-rabbitmq"); + configurator.Host(connectionString); // Apply filters to the send and publish pipelines configurator.ConfigureSend(sendConfig => @@ -205,13 +198,9 @@ public static IServiceCollection AddSsoInfrastructure( #endregion - services.AddDbContext( - options => options.UseNpgsql(configuration.GetConnectionString("SagaConnection")), - ServiceLifetime.Scoped - ); services.AddScoped(); - return services; + return builder; } #endregion diff --git a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Program.cs b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Program.cs index 35d6ee9a..74b36e59 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Program.cs +++ b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Program.cs @@ -18,9 +18,9 @@ await builder.AddApiServices(options => options.SetupHostName = "CouponHost"; options.UseConsulKV = true; options.UseDynamicRequestBodyOperationFilter = false; - options.ConfigureLayers = (services, logger, configuration) => + options.ConfigureLayers = (logger, configuration) => { - services + builder .AddSsoApplication(configuration, logger) .AddSsoInfrastructure(configuration, logger); }; diff --git a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Properties/launchSettings.json b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Properties/launchSettings.json index 7eac031b..0356a68c 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Properties/launchSettings.json +++ b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/Properties/launchSettings.json @@ -2,7 +2,8 @@ "profiles": { "SsoAPI-Development": { "commandName": "Project", - "launchBrowser": false, + "launchBrowser": true, + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.Development.json b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.Development.json index 62c47ec1..7f1e7623 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.Development.json +++ b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.Development.json @@ -9,24 +9,13 @@ } }, "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Seq", - "Args": { - "serverUrl": "http://localhost:5341" - } - } + { "Name": "Console" } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithProperty" ], "Properties": { "Service": "SsoService" } }, - "ConnectionStrings": { - "DefaultConnection": "User ID=postgres;Password=sapass;Server=localhost;Port=5432;Database=AppyNox_Sso", - "TestConnection": "", - "SagaConnection": "User ID=postgres;Password=sapass;Server=localhost;Port=5432;Database=AppyNox_Sso_Saga" - }, "JwtSettings": { "AppyNox": { "SecretKey": "XPFk7n/yI+Sm9DtWlZ/6TYawZs22meQjENPNMmZ9ONA=", @@ -55,18 +44,5 @@ "HealthCheckUrl": "api/health", "HealthCheckIntervalSeconds": 5, "HealthCheckTimeoutSeconds": 5 - }, - "MessageBroker": { - "Host": "rabbitmq://localhost:5672", - "Username": "HappiCorp", - "Password": "HappiCorp" - }, - "NoxMessageBroker": { - "Host": "rabbitmq://localhost:5673", - "Username": "NoxFleetComm", - "Password": "NoxFleetComm" - }, - "Redis": { - "ConnectionString": "localhost:6379" } } \ No newline at end of file diff --git a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.json b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.json index 9a323653..32e2bd51 100644 --- a/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.json +++ b/src/Services/SsoService/AppyNox.Services.Sso.WebAPI/appsettings.json @@ -9,24 +9,13 @@ } }, "WriteTo": [ - { "Name": "Console" }, - { - "Name": "Seq", - "Args": { - "serverUrl": "" - } - } + { "Name": "Console" } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithProperty" ], "Properties": { "Service": "SsoService" } }, - "ConnectionStrings": { - "DefaultConnection": "", - "TestConnection": "", - "SagaConnection": "" - }, "JwtSettings": { "AppyNox": { "SecretKey": "", @@ -54,18 +43,5 @@ "HealthCheckUrl": "", "HealthCheckIntervalSeconds": 5, "HealthCheckTimeoutSeconds": 5 - }, - "MessageBroker": { - "Host": "", - "Username": "", - "Password": "" - }, - "NoxMessageBroker": { - "Host": "", - "Username": "", - "Password": "" - }, - "Redis": { - "ConnectionString": "" } } \ No newline at end of file diff --git a/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/DependencyInjection.cs b/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/DependencyInjection.cs index 530a8df8..21f25011 100644 --- a/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/DependencyInjection.cs +++ b/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/DependencyInjection.cs @@ -6,7 +6,6 @@ using AppyNox.Services.Sso.Server.UI.Services.Layout; using AppyNox.Services.Sso.Server.UI.Services.UserPreferences; using Microsoft.AspNetCore.HttpOverrides; -using MudBlazor; using MudBlazor.Services; using MudExtensions.Services; @@ -14,8 +13,9 @@ namespace AppyNox.Services.Sso.Server.UI; public static class DependencyInjection { - public static IServiceCollection AddServerUI(this IServiceCollection services, IConfiguration config) + public static IHostApplicationBuilder AddServerUI(this IHostApplicationBuilder builder, IConfiguration config) { + IServiceCollection services = builder.Services; services.AddRazorComponents().AddInteractiveServerComponents(); services.AddSignalR(); services.AddCascadingAuthenticationState(); @@ -67,6 +67,6 @@ public static IServiceCollection AddServerUI(this IServiceCollection services, I options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); - return services; + return builder; } } \ No newline at end of file diff --git a/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/Program.cs b/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/Program.cs index 42dfc3da..a4b8cf56 100644 --- a/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/Program.cs +++ b/src/Services/SsoService/Presentation/AppyNox.Services.Sso.Server.UI/Program.cs @@ -1,19 +1,14 @@ using AppyNox.Services.Base.Application.Extensions; -using AppyNox.Services.Base.Application.Interfaces.Loggers; -using AppyNox.Services.Base.Core.Constants; using AppyNox.Services.Base.Infrastructure.Extensions; using AppyNox.Services.Base.Infrastructure.Services.LoggerService; -using AppyNox.Services.Sso.Infrastructure.Hubs; -using AppyNox.Services.Sso.Infrastructure.Localization; -using AppyNox.Services.Sso.Server.UI.Components; -using AppyNox.Services.Sso.Server.UI.Middlewares; -using Microsoft.Extensions.Localization; -using MudBlazor.Services; -using Serilog; using AppyNox.Services.Sso.Application; using AppyNox.Services.Sso.Infrastructure; +using AppyNox.Services.Sso.Infrastructure.Hubs; using AppyNox.Services.Sso.Server.UI; +using AppyNox.Services.Sso.Server.UI.Components; using AppyNox.Services.Sso.Server.UI.Localization; +using Microsoft.Extensions.Localization; +using Serilog; var builder = WebApplication.CreateBuilder(args); @@ -53,7 +48,7 @@ #region [ Dependency Injection For Layers ] noxLogger.LogInformation("Registering DI's for layers."); -builder.Services.AddSsoApplication(configuration, noxLogger) +builder.AddSsoApplication(configuration, noxLogger) .AddSsoInfrastructure(configuration, noxLogger, true) .AddServerUI(builder.Configuration); noxLogger.LogInformation("Registering DI's for layers completed.");