Files
demo-contact/ui/Sufi.Demo.PeopleDirectory.UI/Server/StartupExtensions.cs
2026-02-03 10:44:31 +08:00

130 lines
3.9 KiB
C#

using Microsoft.EntityFrameworkCore;
using Serilog;
using Sufi.Demo.PeopleDirectory.Application.Extensions;
using Sufi.Demo.PeopleDirectory.Infrastructure;
using Sufi.Demo.PeopleDirectory.Persistence.Contexts;
using Sufi.Demo.PeopleDirectory.Persistence.Extensions;
using Sufi.Demo.PeopleDirectory.UI.Server.Extensions;
using Sufi.Demo.PeopleDirectory.UI.Server.Options;
using System.Threading.RateLimiting;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Sufi.Demo.PeopleDirectory.UI.Server
{
public static class StartupExtensions
{
public static WebApplication ConfigureServices(this WebApplicationBuilder builder)
{
var configuration = builder.Configuration;
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
builder.Host.UseSerilog();
var rateLimitOptions = configuration.GetSection("RateLimit").Get<RateLimitOptions>()!;
var services = builder.Services;
var licenseKey = configuration.GetValue<string>("LuckyPennyLicenseKey") ?? string.Empty;
// Add services to the container.
services.AddHttpContextAccessor();
services.AddApplicationLayer(licenseKey)
.AddInfrastructureServices()
.AddPersistenceServices(configuration);
services.AddControllersWithViews();
services.AddRazorPages();
services.AddHealthChecks();
services.AddRateLimiter(options =>
{
// Apply for all requests.
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: partition => new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = rateLimitOptions.PermitLimit,
Window = TimeSpan.FromSeconds(rateLimitOptions.Window)
}));
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});
// Register Swagger services.
services.AddEndpointsApiExplorer();
services.RegisterSwagger();
return builder.Build();
}
public static WebApplication ConfigurePipeline(this WebApplication app)
{
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
diagnosticContext.Set("UserAgent", httpContext.Request.Headers.UserAgent);
diagnosticContext.Set("ClientIP", httpContext.Connection.RemoteIpAddress?.ToString() ?? "");
};
});
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
app.ConfigureSwagger();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseRateLimiter();
app.MapHealthChecks("/health");
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
return app;
}
public static void ConfigureSwagger(this IApplicationBuilder app)
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.RoutePrefix = "swagger";
options.DisplayRequestDuration();
foreach (var desc in ((IEndpointRouteBuilder)app).DescribeApiVersions())
{
options.SwaggerEndpoint($"{desc.GroupName}/swagger.json",
desc.GroupName.ToUpperInvariant());
}
});
}
public static async Task<IApplicationBuilder> EnsureDatabaseMigrationAsync(this IApplicationBuilder app)
{
using (var scope = app.ApplicationServices.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await dbContext.Database.MigrateAsync();
}
return app;
}
}
}