diff --git a/src/Services/Booking/src/Booking.Api/Program.cs b/src/Services/Booking/src/Booking.Api/Program.cs index 81e0a81..169e7d3 100644 --- a/src/Services/Booking/src/Booking.Api/Program.cs +++ b/src/Services/Booking/src/Booking.Api/Program.cs @@ -1,6 +1,7 @@ using Booking; using Booking.Data; using Booking.Extensions; +using Booking.Extensions.Infrastructure; using BuildingBlocks.EventStoreDB; using BuildingBlocks.HealthCheck; using BuildingBlocks.IdsGenerator; @@ -21,66 +22,16 @@ using Prometheus; using Serilog; var builder = WebApplication.CreateBuilder(args); -var configuration = builder.Configuration; -var env = builder.Environment; - -var appOptions = builder.Services.GetOptions("AppOptions"); - -Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); - -builder.Services.AddPersistMessage(configuration); -builder.Services.AddMongoDbContext(configuration); - -builder.AddCustomSerilog(env); -builder.Services.AddCore(); -builder.Services.AddJwt(); -builder.Services.AddHttpContextAccessor(); -builder.Services.AddCustomSwagger(configuration, typeof(BookingRoot).Assembly); -builder.Services.AddCustomVersioning(); -builder.Services.AddCustomMediatR(); -builder.Services.AddValidatorsFromAssembly(typeof(BookingRoot).Assembly); -builder.Services.AddCustomProblemDetails(); -builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly); -builder.Services.AddCustomHealthCheck(); -builder.Services.AddCustomMassTransit(typeof(BookingRoot).Assembly, env); -builder.Services.AddCustomOpenTelemetry(); -builder.Services.AddTransient(); - -SnowFlakIdGenerator.Configure(3); - -// ref: https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample/EventStoreDB/ECommerce -builder.Services.AddEventStore(configuration, typeof(BookingRoot).Assembly) - .AddEventStoreDBSubscriptionToAll(); - -builder.Services.AddGrpcClients(); builder.AddMinimalEndpoints(); +builder.AddInfrastructure(); var app = builder.Build(); -app.UseSerilogRequestLogging(); -app.UseCorrelationId(); -app.UseRouting(); -app.UseHttpMetrics(); -app.UseHttpsRedirection(); +app.MapMinimalEndpoints(); app.UseAuthentication(); app.UseAuthorization(); -app.UseProblemDetails(); -app.UseCustomHealthCheck(); - -app.MapMinimalEndpoints(); - -app.UseEndpoints(endpoints => -{ - endpoints.MapMetrics(); -}); - -app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); - -if (app.Environment.IsDevelopment()) -{ - app.UseCustomSwagger(); -} +app.UseInfrastructure(); app.Run(); diff --git a/src/Services/Booking/src/Booking/Extensions/CoreExtensions.cs b/src/Services/Booking/src/Booking/Extensions/CoreExtensions.cs deleted file mode 100644 index d2cd99f..0000000 --- a/src/Services/Booking/src/Booking/Extensions/CoreExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using BuildingBlocks.Core; -using BuildingBlocks.Utils; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; - -namespace Booking.Extensions; - -public static class CoreExtensions -{ - public static IServiceCollection AddCore(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.Configure(options => - { - options.SuppressModelStateInvalidFilter = true; - }); - - return services; - } -} diff --git a/src/Services/Booking/src/Booking/Extensions/GrpcClientExtensions.cs b/src/Services/Booking/src/Booking/Extensions/Infrastructure/GrpcClientExtensions.cs similarity index 94% rename from src/Services/Booking/src/Booking/Extensions/GrpcClientExtensions.cs rename to src/Services/Booking/src/Booking/Extensions/Infrastructure/GrpcClientExtensions.cs index 8dbbfdd..f48b0ad 100644 --- a/src/Services/Booking/src/Booking/Extensions/GrpcClientExtensions.cs +++ b/src/Services/Booking/src/Booking/Extensions/Infrastructure/GrpcClientExtensions.cs @@ -4,7 +4,7 @@ using Flight; using Microsoft.Extensions.DependencyInjection; using Passenger; -namespace Booking.Extensions; +namespace Booking.Extensions.Infrastructure; public static class GrpcClientExtensions { diff --git a/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs new file mode 100644 index 0000000..55f1a9f --- /dev/null +++ b/src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs @@ -0,0 +1,113 @@ +using System.Threading.RateLimiting; +using Booking.Data; +using BuildingBlocks.Core; +using BuildingBlocks.EventStoreDB; +using BuildingBlocks.HealthCheck; +using BuildingBlocks.IdsGenerator; +using BuildingBlocks.Jwt; +using BuildingBlocks.Logging; +using BuildingBlocks.Mapster; +using BuildingBlocks.MassTransit; +using BuildingBlocks.Mongo; +using BuildingBlocks.OpenTelemetry; +using BuildingBlocks.PersistMessageProcessor; +using BuildingBlocks.Swagger; +using BuildingBlocks.Utils; +using BuildingBlocks.Web; +using Figgle; +using FluentValidation; +using Hellang.Middleware.ProblemDetails; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Prometheus; +using Serilog; + +namespace Booking.Extensions.Infrastructure; + +public static class InfrastructureExtensions +{ + public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder) + { + var configuration = builder.Configuration; + var env = builder.Environment; + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.Configure(options => + { + options.SuppressModelStateInvalidFilter = true; + }); + + var appOptions = builder.Services.GetOptions("AppOptions"); + + Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); + + builder.Services.AddRateLimiter(options => + { + options.GlobalLimiter = PartitionedRateLimiter.Create(httpContext => + RateLimitPartition.GetFixedWindowLimiter( + partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(), + factory: partition => new FixedWindowRateLimiterOptions + { + AutoReplenishment = true, PermitLimit = 10, QueueLimit = 0, Window = TimeSpan.FromMinutes(1) + })); + }); + + builder.Services.AddPersistMessage(configuration); + builder.Services.AddMongoDbContext(configuration); + + builder.AddCustomSerilog(env); + builder.Services.AddJwt(); + builder.Services.AddHttpContextAccessor(); + builder.Services.AddCustomSwagger(configuration, typeof(BookingRoot).Assembly); + builder.Services.AddCustomVersioning(); + builder.Services.AddCustomMediatR(); + builder.Services.AddValidatorsFromAssembly(typeof(BookingRoot).Assembly); + builder.Services.AddCustomProblemDetails(); + builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly); + builder.Services.AddCustomHealthCheck(); + builder.Services.AddCustomMassTransit(typeof(BookingRoot).Assembly, env); + builder.Services.AddCustomOpenTelemetry(); + builder.Services.AddTransient(); + + SnowFlakIdGenerator.Configure(3); + +// ref: https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample/EventStoreDB/ECommerce + builder.Services.AddEventStore(configuration, typeof(BookingRoot).Assembly) + .AddEventStoreDBSubscriptionToAll(); + + builder.Services.AddGrpcClients(); + + return builder; + } + + + public static WebApplication UseInfrastructure(this WebApplication app) + { + var env = app.Environment; + var appOptions = app.GetOptions("AppOptions"); + + app.UseSerilogRequestLogging(); + app.UseCorrelationId(); + app.UseRouting(); + app.UseHttpMetrics(); + app.UseHttpsRedirection(); + + app.UseProblemDetails(); + app.UseCustomHealthCheck(); + app.MapMetrics(); + app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); + + if (env.IsDevelopment()) + { + app.UseCustomSwagger(); + } + + return app; + } +} diff --git a/src/Services/Booking/src/Booking/Extensions/MediatRExtensions.cs b/src/Services/Booking/src/Booking/Extensions/Infrastructure/MediatRExtensions.cs similarity index 89% rename from src/Services/Booking/src/Booking/Extensions/MediatRExtensions.cs rename to src/Services/Booking/src/Booking/Extensions/Infrastructure/MediatRExtensions.cs index 72514c7..f4bda39 100644 --- a/src/Services/Booking/src/Booking/Extensions/MediatRExtensions.cs +++ b/src/Services/Booking/src/Booking/Extensions/Infrastructure/MediatRExtensions.cs @@ -1,10 +1,9 @@ -using BuildingBlocks.EFCore; using BuildingBlocks.Logging; using BuildingBlocks.Validation; using MediatR; using Microsoft.Extensions.DependencyInjection; -namespace Booking.Extensions; +namespace Booking.Extensions.Infrastructure; public static class MediatRExtensions { diff --git a/src/Services/Booking/src/Booking/Extensions/ProblemDetailsExtensions.cs b/src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs similarity index 98% rename from src/Services/Booking/src/Booking/Extensions/ProblemDetailsExtensions.cs rename to src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs index 68022aa..ce6a01e 100644 --- a/src/Services/Booking/src/Booking/Extensions/ProblemDetailsExtensions.cs +++ b/src/Services/Booking/src/Booking/Extensions/Infrastructure/ProblemDetailsExtensions.cs @@ -5,9 +5,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; -namespace Booking.Extensions; +namespace Booking.Extensions.Infrastructure; public static class ProblemDetailsExtensions { diff --git a/src/Services/Flight/src/Flight.Api/Program.cs b/src/Services/Flight/src/Flight.Api/Program.cs index ecfddc2..ae85e47 100644 --- a/src/Services/Flight/src/Flight.Api/Program.cs +++ b/src/Services/Flight/src/Flight.Api/Program.cs @@ -1,99 +1,18 @@ -using System.Reflection; -using BuildingBlocks.Caching; -using BuildingBlocks.EFCore; -using BuildingBlocks.Exception; -using BuildingBlocks.HealthCheck; -using BuildingBlocks.IdsGenerator; -using BuildingBlocks.Jwt; -using BuildingBlocks.Logging; -using BuildingBlocks.Mapster; -using BuildingBlocks.MassTransit; -using BuildingBlocks.Mongo; -using BuildingBlocks.OpenTelemetry; -using BuildingBlocks.PersistMessageProcessor; -using BuildingBlocks.Swagger; using BuildingBlocks.Web; -using Figgle; -using Flight; -using Flight.Data; -using Flight.Data.Seed; -using Flight.Extensions; -using Flight.Flights.Features.CreateFlight.Endpoints.V1; -using Flight.GrpcServer.Services; -using FluentValidation; -using Hellang.Middleware.ProblemDetails; -using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Prometheus; -using Serilog; +using Flight.Extensions.Infrastructure; var builder = WebApplication.CreateBuilder(args); -var configuration = builder.Configuration; -var env = builder.Environment; - -var appOptions = builder.Services.GetOptions("AppOptions"); -Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); - -builder.Services.AddCustomDbContext(configuration); -builder.Services.AddScoped(); - -builder.Services.AddMongoDbContext(configuration); -builder.Services.AddPersistMessage(configuration); - -builder.AddCustomSerilog(env); -builder.Services.AddCore(); -builder.Services.AddJwt(); -builder.Services.AddCustomSwagger(configuration, typeof(FlightRoot).Assembly); -builder.Services.AddCustomVersioning(); -builder.Services.AddCustomMediatR(); -builder.Services.AddValidatorsFromAssembly(typeof(FlightRoot).Assembly); -builder.Services.AddCustomProblemDetails(); -builder.Services.AddCustomMapster(typeof(FlightRoot).Assembly); -builder.Services.AddHttpContextAccessor(); -builder.Services.AddCustomMassTransit(typeof(FlightRoot).Assembly, env); -builder.Services.AddCustomOpenTelemetry(); -builder.Services.AddRouting(options => options.LowercaseUrls = true); -builder.Services.AddCustomHealthCheck(); - -builder.Services.AddGrpc(options => -{ - options.Interceptors.Add(); -}); - -SnowFlakIdGenerator.Configure(1); - -builder.Services.AddCachingRequest(new List {typeof(FlightRoot).Assembly}); - -builder.Services.AddEasyCaching(options => { options.UseInMemory(configuration, "mem"); }); builder.AddMinimalEndpoints(); +builder.AddInfrastructure(); var app = builder.Build(); -app.UseSerilogRequestLogging(); -app.UseCorrelationId(); -app.UseRouting(); -app.UseHttpMetrics(); -app.UseMigration(env); -app.UseProblemDetails(); -app.UseHttpsRedirection(); -app.UseCustomHealthCheck(); +// ref: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-7.0#routing-basics +app.MapMinimalEndpoints(); app.UseAuthentication(); app.UseAuthorization(); - -app.MapMinimalEndpoints(); - -app.UseEndpoints(endpoints => -{ - endpoints.MapMetrics(); - endpoints.MapGrpcService(); -}); - -app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); - -if (app.Environment.IsDevelopment()) -{ - app.UseCustomSwagger(); -} +app.UseInfrastructure(); app.Run(); diff --git a/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs b/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs index 02efcb8..baa9e78 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Features/CreateAircraft/Endpoints/V1/CreateAircraftEndpoint.cs @@ -9,6 +9,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; +namespace Flight.Aircrafts.Features.CreateAircraft.Endpoints.V1; + public class CreateAircraftEndpoint : IMinimalEndpoint { public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) diff --git a/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs b/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs index 9bd67d9..4862435 100644 --- a/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs +++ b/src/Services/Flight/src/Flight/Airports/Features/CreateAirport/Endpoints/V1/CreateAirportEndpoint.cs @@ -9,6 +9,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Swashbuckle.AspNetCore.Annotations; +namespace Flight.Airports.Features.CreateAirport.Endpoints.V1; + public class CreateAirportEndpoint : IMinimalEndpoint { public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints) diff --git a/src/Services/Flight/src/Flight/Extensions/CoreExtensions.cs b/src/Services/Flight/src/Flight/Extensions/CoreExtensions.cs deleted file mode 100644 index a6a5762..0000000 --- a/src/Services/Flight/src/Flight/Extensions/CoreExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using BuildingBlocks.Core; -using BuildingBlocks.Utils; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; - -namespace Flight.Extensions; - -public static class CoreExtensions -{ - public static IServiceCollection AddCore(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.Configure(options => - { - options.SuppressModelStateInvalidFilter = true; - }); - - return services; - } -} diff --git a/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs new file mode 100644 index 0000000..f6d7604 --- /dev/null +++ b/src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.RateLimiting; +using BuildingBlocks.Caching; +using BuildingBlocks.Core; +using BuildingBlocks.EFCore; +using BuildingBlocks.Exception; +using BuildingBlocks.HealthCheck; +using BuildingBlocks.IdsGenerator; +using BuildingBlocks.Jwt; +using BuildingBlocks.Logging; +using BuildingBlocks.Mapster; +using BuildingBlocks.MassTransit; +using BuildingBlocks.Mongo; +using BuildingBlocks.OpenTelemetry; +using BuildingBlocks.PersistMessageProcessor; +using BuildingBlocks.Swagger; +using BuildingBlocks.Utils; +using BuildingBlocks.Web; +using Figgle; +using Flight.Data; +using Flight.Data.Seed; +using Flight.GrpcServer.Services; +using FluentValidation; +using Hellang.Middleware.ProblemDetails; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Prometheus; +using Serilog; + +namespace Flight.Extensions.Infrastructure; + +public static class InfrastructureExtensions +{ + public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder) + { + var configuration = builder.Configuration; + var env = builder.Environment; + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.Configure(options => + { + options.SuppressModelStateInvalidFilter = true; + }); + + builder.Services.AddCustomMediatR(); + builder.Services.AddCustomProblemDetails(); + + var appOptions = builder.Services.GetOptions("AppOptions"); + Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); + + builder.Services.AddRateLimiter(options => + { + options.GlobalLimiter = PartitionedRateLimiter.Create(httpContext => + RateLimitPartition.GetFixedWindowLimiter( + partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(), + factory: partition => new FixedWindowRateLimiterOptions + { + AutoReplenishment = true, PermitLimit = 10, QueueLimit = 0, Window = TimeSpan.FromMinutes(1) + })); + }); + + builder.Services.AddCustomDbContext(configuration); + builder.Services.AddScoped(); + + builder.Services.AddMongoDbContext(configuration); + builder.Services.AddPersistMessage(configuration); + + builder.AddCustomSerilog(env); + builder.Services.AddJwt(); + builder.Services.AddCustomSwagger(configuration, typeof(FlightRoot).Assembly); + builder.Services.AddCustomVersioning(); + builder.Services.AddValidatorsFromAssembly(typeof(FlightRoot).Assembly); + builder.Services.AddCustomMapster(typeof(FlightRoot).Assembly); + builder.Services.AddHttpContextAccessor(); + builder.Services.AddCustomMassTransit(typeof(FlightRoot).Assembly, env); + builder.Services.AddCustomOpenTelemetry(); + builder.Services.AddCustomHealthCheck(); + + builder.Services.AddGrpc(options => + { + options.Interceptors.Add(); + }); + + SnowFlakIdGenerator.Configure(1); + + builder.Services.AddCachingRequest(new List {typeof(FlightRoot).Assembly}); + + builder.Services.AddEasyCaching(options => { options.UseInMemory(configuration, "mem"); }); + + return builder; + } + + + public static WebApplication UseInfrastructure(this WebApplication app) + { + var env = app.Environment; + var appOptions = app.GetOptions("AppOptions"); + + app.UseSerilogRequestLogging(); + app.UseCorrelationId(); + app.UseHttpMetrics(); + app.UseMigration(env); + app.UseProblemDetails(); + app.UseHttpsRedirection(); + app.MapMetrics(); + app.UseCustomHealthCheck(); + app.MapGrpcService(); + app.UseRateLimiter(); + app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); + + if (env.IsDevelopment()) + { + app.UseCustomSwagger(); + } + + return app; + } +} diff --git a/src/Services/Flight/src/Flight/Extensions/MediatRExtensions.cs b/src/Services/Flight/src/Flight/Extensions/Infrastructure/MediatRExtensions.cs similarity index 94% rename from src/Services/Flight/src/Flight/Extensions/MediatRExtensions.cs rename to src/Services/Flight/src/Flight/Extensions/Infrastructure/MediatRExtensions.cs index 6ca8a8f..540ae22 100644 --- a/src/Services/Flight/src/Flight/Extensions/MediatRExtensions.cs +++ b/src/Services/Flight/src/Flight/Extensions/Infrastructure/MediatRExtensions.cs @@ -5,7 +5,7 @@ using BuildingBlocks.Validation; using MediatR; using Microsoft.Extensions.DependencyInjection; -namespace Flight.Extensions; +namespace Flight.Extensions.Infrastructure; public static class MediatRExtensions { diff --git a/src/Services/Flight/src/Flight/Extensions/ProblemDetailsExtensions.cs b/src/Services/Flight/src/Flight/Extensions/Infrastructure/ProblemDetailsExtensions.cs similarity index 100% rename from src/Services/Flight/src/Flight/Extensions/ProblemDetailsExtensions.cs rename to src/Services/Flight/src/Flight/Extensions/Infrastructure/ProblemDetailsExtensions.cs diff --git a/src/Services/Identity/src/Identity.Api/Program.cs b/src/Services/Identity/src/Identity.Api/Program.cs index 0e4d4fa..60930e0 100644 --- a/src/Services/Identity/src/Identity.Api/Program.cs +++ b/src/Services/Identity/src/Identity.Api/Program.cs @@ -1,85 +1,21 @@ -using BuildingBlocks.EFCore; -using BuildingBlocks.HealthCheck; -using BuildingBlocks.IdsGenerator; -using BuildingBlocks.Logging; -using BuildingBlocks.Mapster; -using BuildingBlocks.MassTransit; -using BuildingBlocks.OpenTelemetry; -using BuildingBlocks.PersistMessageProcessor; -using BuildingBlocks.Swagger; using BuildingBlocks.Web; -using Figgle; -using FluentValidation; -using Hellang.Middleware.ProblemDetails; -using Identity; -using Identity.Data; -using Identity.Data.Seed; -using Identity.Extensions; -using Prometheus; -using Serilog; +using Identity.Extensions.Infrastructure; var builder = WebApplication.CreateBuilder(args); -var configuration = builder.Configuration; -var env = builder.Environment; - -var appOptions = builder.Services.GetOptions("AppOptions"); -Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); - -builder.Services.AddPersistMessage(configuration); -builder.Services.AddCustomDbContext(configuration); -builder.Services.AddScoped(); -builder.Services.AddCore(); -builder.Services.AddControllers(); -builder.AddCustomSerilog(env); -builder.Services.AddCustomSwagger(configuration, typeof(IdentityRoot).Assembly); -builder.Services.AddCustomVersioning(); -builder.Services.AddCustomMediatR(); -builder.Services.AddValidatorsFromAssembly(typeof(IdentityRoot).Assembly); -builder.Services.AddCustomProblemDetails(); -builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly); -builder.Services.AddCustomHealthCheck(); - -builder.Services.AddCustomMassTransit(typeof(IdentityRoot).Assembly, env); -builder.Services.AddCustomOpenTelemetry(); - -SnowFlakIdGenerator.Configure(4); - -builder.Services.AddIdentityServer(env); builder.AddMinimalEndpoints(); +builder.AddInfrastructure(); var app = builder.Build(); -app.UseSerilogRequestLogging(); -app.UseMigration(env); -app.UseCorrelationId(); -app.UseRouting(); -app.UseHttpMetrics(); -app.UseProblemDetails(); -app.UseHttpsRedirection(); -app.UseCustomHealthCheck(); +app.MapMinimalEndpoints(); app.UseAuthentication(); app.UseAuthorization(); -app.UseIdentityServer(); - -app.MapMinimalEndpoints(); - -app.UseEndpoints(endpoints => -{ - endpoints.MapControllers(); - endpoints.MapMetrics(); -}); - -app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); - -if (app.Environment.IsDevelopment()) -{ - app.UseCustomSwagger(); -} +app.UseInfrastructure(); app.Run(); namespace Identity.Api { - public partial class Program {} + public partial class Program { } } diff --git a/src/Services/Identity/src/Identity/Extensions/CoreExtensions.cs b/src/Services/Identity/src/Identity/Extensions/CoreExtensions.cs deleted file mode 100644 index f914c33..0000000 --- a/src/Services/Identity/src/Identity/Extensions/CoreExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using BuildingBlocks.Core; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; - -namespace Identity.Extensions; - -public static class CoreExtensions -{ - public static IServiceCollection AddCore(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - - services.Configure(options => - { - options.SuppressModelStateInvalidFilter = true; - }); - - return services; - } -} diff --git a/src/Services/Identity/src/Identity/Extensions/IdentityServerExtensions.cs b/src/Services/Identity/src/Identity/Extensions/Infrastructure/IdentityServerExtensions.cs similarity index 97% rename from src/Services/Identity/src/Identity/Extensions/IdentityServerExtensions.cs rename to src/Services/Identity/src/Identity/Extensions/Infrastructure/IdentityServerExtensions.cs index d2358c2..dee8487 100644 --- a/src/Services/Identity/src/Identity/Extensions/IdentityServerExtensions.cs +++ b/src/Services/Identity/src/Identity/Extensions/Infrastructure/IdentityServerExtensions.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Identity.Extensions; +namespace Identity.Extensions.Infrastructure; public static class IdentityServerExtensions { diff --git a/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs new file mode 100644 index 0000000..65bcd92 --- /dev/null +++ b/src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs @@ -0,0 +1,106 @@ +using System; +using System.Threading.RateLimiting; +using BuildingBlocks.Core; +using BuildingBlocks.EFCore; +using BuildingBlocks.HealthCheck; +using BuildingBlocks.IdsGenerator; +using BuildingBlocks.Logging; +using BuildingBlocks.Mapster; +using BuildingBlocks.MassTransit; +using BuildingBlocks.OpenTelemetry; +using BuildingBlocks.PersistMessageProcessor; +using BuildingBlocks.Swagger; +using BuildingBlocks.Web; +using Figgle; +using FluentValidation; +using Hellang.Middleware.ProblemDetails; +using Identity.Data; +using Identity.Data.Seed; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Prometheus; +using Serilog; + +namespace Identity.Extensions.Infrastructure; + +public static class InfrastructureExtensions +{ + public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder) + { + var configuration = builder.Configuration; + var env = builder.Environment; + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.Configure(options => + { + options.SuppressModelStateInvalidFilter = true; + }); + + var appOptions = builder.Services.GetOptions("AppOptions"); + Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); + + builder.Services.AddRateLimiter(options => + { + options.GlobalLimiter = PartitionedRateLimiter.Create(httpContext => + RateLimitPartition.GetFixedWindowLimiter( + partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(), + factory: partition => new FixedWindowRateLimiterOptions + { + AutoReplenishment = true, PermitLimit = 10, QueueLimit = 0, Window = TimeSpan.FromMinutes(1) + })); + }); + + builder.Services.AddControllers(); + builder.Services.AddPersistMessage(configuration); + builder.Services.AddCustomDbContext(configuration); + builder.Services.AddScoped(); + builder.AddCustomSerilog(env); + builder.Services.AddCustomSwagger(configuration, typeof(IdentityRoot).Assembly); + builder.Services.AddCustomVersioning(); + builder.Services.AddCustomMediatR(); + builder.Services.AddValidatorsFromAssembly(typeof(IdentityRoot).Assembly); + builder.Services.AddCustomProblemDetails(); + builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly); + builder.Services.AddCustomHealthCheck(); + + builder.Services.AddCustomMassTransit(typeof(IdentityRoot).Assembly, env); + builder.Services.AddCustomOpenTelemetry(); + + SnowFlakIdGenerator.Configure(4); + + builder.Services.AddIdentityServer(env); + + return builder; + } + + + public static WebApplication UseInfrastructure(this WebApplication app) + { + var env = app.Environment; + var appOptions = app.GetOptions("AppOptions"); + + app.UseSerilogRequestLogging(); + app.UseMigration(env); + app.UseCorrelationId(); + app.UseHttpMetrics(); + app.UseProblemDetails(); + app.UseHttpsRedirection(); + app.UseCustomHealthCheck(); + app.UseIdentityServer(); + app.MapMetrics(); + + app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); + + if (env.IsDevelopment()) + { + app.UseCustomSwagger(); + } + + return app; + } +} diff --git a/src/Services/Identity/src/Identity/Extensions/MediatRExtensions.cs b/src/Services/Identity/src/Identity/Extensions/Infrastructure/MediatRExtensions.cs similarity index 89% rename from src/Services/Identity/src/Identity/Extensions/MediatRExtensions.cs rename to src/Services/Identity/src/Identity/Extensions/Infrastructure/MediatRExtensions.cs index 9b0043d..3671165 100644 --- a/src/Services/Identity/src/Identity/Extensions/MediatRExtensions.cs +++ b/src/Services/Identity/src/Identity/Extensions/Infrastructure/MediatRExtensions.cs @@ -1,10 +1,9 @@ -using BuildingBlocks.EFCore; using BuildingBlocks.Logging; using BuildingBlocks.Validation; using MediatR; using Microsoft.Extensions.DependencyInjection; -namespace Identity.Extensions; +namespace Identity.Extensions.Infrastructure; public static class MediatRExtensions { diff --git a/src/Services/Identity/src/Identity/Extensions/ProblemDetailsExtensions.cs b/src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs similarity index 98% rename from src/Services/Identity/src/Identity/Extensions/ProblemDetailsExtensions.cs rename to src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs index 2455b6e..4fda59a 100644 --- a/src/Services/Identity/src/Identity/Extensions/ProblemDetailsExtensions.cs +++ b/src/Services/Identity/src/Identity/Extensions/Infrastructure/ProblemDetailsExtensions.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Identity.Extensions; +namespace Identity.Extensions.Infrastructure; public static class ProblemDetailsExtensions { diff --git a/src/Services/Passenger/src/Passenger.Api/Program.cs b/src/Services/Passenger/src/Passenger.Api/Program.cs index fc15fbf..a7e37c2 100644 --- a/src/Services/Passenger/src/Passenger.Api/Program.cs +++ b/src/Services/Passenger/src/Passenger.Api/Program.cs @@ -18,70 +18,23 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Passenger; using Passenger.Data; using Passenger.Extensions; +using Passenger.Extensions.Infrastructure; using Passenger.GrpcServer.Services; using Prometheus; using Serilog; var builder = WebApplication.CreateBuilder(args); -var configuration = builder.Configuration; -var env = builder.Environment; -var appOptions = builder.Services.GetOptions("AppOptions"); -Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); - -builder.Services.AddCustomDbContext(configuration); -builder.Services.AddMongoDbContext(configuration); -builder.Services.AddPersistMessage(configuration); - -builder.AddCustomSerilog(env); -builder.Services.AddCore(); -builder.Services.AddJwt(); -builder.Services.AddCustomSwagger(configuration, typeof(PassengerRoot).Assembly); -builder.Services.AddCustomVersioning(); -builder.Services.AddCustomMediatR(); -builder.Services.AddValidatorsFromAssembly(typeof(PassengerRoot).Assembly); -builder.Services.AddCustomProblemDetails(); -builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly); -builder.Services.AddHttpContextAccessor(); -builder.Services.AddCustomHealthCheck(); -builder.Services.AddCustomMassTransit(typeof(PassengerRoot).Assembly, env); -builder.Services.AddCustomOpenTelemetry(); -builder.Services.AddGrpc(options => -{ - options.Interceptors.Add(); -}); - -SnowFlakIdGenerator.Configure(2); builder.AddMinimalEndpoints(); +builder.AddInfrastructure(); var app = builder.Build(); -app.UseSerilogRequestLogging(); -app.UseMigration(env); -app.UseCorrelationId(); -app.UseRouting(); -app.UseHttpMetrics(); -app.UseProblemDetails(); -app.UseHttpsRedirection(); +app.MapMinimalEndpoints(); app.UseAuthentication(); app.UseAuthorization(); -app.UseCustomHealthCheck(); - -app.MapMinimalEndpoints(); - -app.UseEndpoints(endpoints => -{ - endpoints.MapMetrics(); - endpoints.MapGrpcService(); -}); - -app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); - -if (app.Environment.IsDevelopment()) -{ - app.UseCustomSwagger(); -} +app.UseInfrastructure(); app.Run(); diff --git a/src/Services/Passenger/src/Passenger/Extensions/CoreExtensions.cs b/src/Services/Passenger/src/Passenger/Extensions/CoreExtensions.cs deleted file mode 100644 index 3cc6e0e..0000000 --- a/src/Services/Passenger/src/Passenger/Extensions/CoreExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using BuildingBlocks.Core; -using BuildingBlocks.Utils; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; - -namespace Passenger.Extensions; - -public static class CoreExtensions -{ - public static IServiceCollection AddCore(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.Configure(options => - { - options.SuppressModelStateInvalidFilter = true; - }); - - return services; - } -} diff --git a/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs new file mode 100644 index 0000000..9c9e3f1 --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs @@ -0,0 +1,112 @@ +using System.Threading.RateLimiting; +using BuildingBlocks.Core; +using BuildingBlocks.EFCore; +using BuildingBlocks.Exception; +using BuildingBlocks.HealthCheck; +using BuildingBlocks.IdsGenerator; +using BuildingBlocks.Jwt; +using BuildingBlocks.Logging; +using BuildingBlocks.Mapster; +using BuildingBlocks.MassTransit; +using BuildingBlocks.Mongo; +using BuildingBlocks.OpenTelemetry; +using BuildingBlocks.PersistMessageProcessor; +using BuildingBlocks.Swagger; +using BuildingBlocks.Utils; +using BuildingBlocks.Web; +using Figgle; +using FluentValidation; +using Hellang.Middleware.ProblemDetails; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Passenger.Data; +using Passenger.GrpcServer.Services; +using Prometheus; +using Serilog; + +namespace Passenger.Extensions.Infrastructure; + +public static class InfrastructureExtensions +{ + public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder) + { + var configuration = builder.Configuration; + var env = builder.Environment; + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.Configure(options => + { + options.SuppressModelStateInvalidFilter = true; + }); + + var appOptions = builder.Services.GetOptions("AppOptions"); + Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name)); + + builder.Services.AddRateLimiter(options => + { + options.GlobalLimiter = PartitionedRateLimiter.Create(httpContext => + RateLimitPartition.GetFixedWindowLimiter( + partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(), + factory: partition => new FixedWindowRateLimiterOptions + { + AutoReplenishment = true, PermitLimit = 10, QueueLimit = 0, Window = TimeSpan.FromMinutes(1) + })); + }); + + builder.Services.AddCustomDbContext(configuration); + builder.Services.AddMongoDbContext(configuration); + builder.Services.AddPersistMessage(configuration); + + builder.AddCustomSerilog(env); + builder.Services.AddJwt(); + builder.Services.AddCustomSwagger(configuration, typeof(PassengerRoot).Assembly); + builder.Services.AddCustomVersioning(); + builder.Services.AddCustomMediatR(); + builder.Services.AddValidatorsFromAssembly(typeof(PassengerRoot).Assembly); + builder.Services.AddCustomProblemDetails(); + builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly); + builder.Services.AddHttpContextAccessor(); + builder.Services.AddCustomHealthCheck(); + builder.Services.AddCustomMassTransit(typeof(PassengerRoot).Assembly, env); + builder.Services.AddCustomOpenTelemetry(); + builder.Services.AddGrpc(options => + { + options.Interceptors.Add(); + }); + + SnowFlakIdGenerator.Configure(2); + + return builder; + } + + + public static WebApplication UseInfrastructure(this WebApplication app) + { + var env = app.Environment; + var appOptions = app.GetOptions("AppOptions"); + + app.UseSerilogRequestLogging(); + app.UseMigration(env); + app.UseCorrelationId(); + app.UseHttpMetrics(); + app.UseProblemDetails(); + app.UseHttpsRedirection(); + app.UseCustomHealthCheck(); + app.MapMetrics(); + app.MapGrpcService(); + app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); + + if (env.IsDevelopment()) + { + app.UseCustomSwagger(); + } + + return app; + } +} diff --git a/src/Services/Passenger/src/Passenger/Extensions/MediatRExtensions.cs b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/MediatRExtensions.cs similarity index 100% rename from src/Services/Passenger/src/Passenger/Extensions/MediatRExtensions.cs rename to src/Services/Passenger/src/Passenger/Extensions/Infrastructure/MediatRExtensions.cs diff --git a/src/Services/Passenger/src/Passenger/Extensions/ProblemDetailsExtensions.cs b/src/Services/Passenger/src/Passenger/Extensions/Infrastructure/ProblemDetailsExtensions.cs similarity index 100% rename from src/Services/Passenger/src/Passenger/Extensions/ProblemDetailsExtensions.cs rename to src/Services/Passenger/src/Passenger/Extensions/Infrastructure/ProblemDetailsExtensions.cs