using Microsoft.EntityFrameworkCore; using Asp.Versioning; using FluentValidation; using Hellang.Middleware.ProblemDetails; using BookingService.API.Application.Behaviors; using BookingService.Infrastructure; using Serilog; // EN: Configure Serilog early / VI: Cấu hình Serilog sớm Log.Logger = new LoggerConfiguration() .WriteTo.Console() .CreateBootstrapLogger(); try { Log.Information("Starting BookingService API / Khởi động BookingService API"); var builder = WebApplication.CreateBuilder(args); // EN: Configure Serilog / VI: Cấu hình Serilog builder.Host.UseSerilog((context, services, configuration) => configuration .ReadFrom.Configuration(context.Configuration) .ReadFrom.Services(services) .Enrich.FromLogContext() .WriteTo.Console()); // EN: Add Infrastructure services / VI: Thêm Infrastructure services builder.Services.AddInfrastructure(builder.Configuration); // EN: Add MediatR with behaviors / VI: Thêm MediatR với behaviors builder.Services.AddMediatR(cfg => { cfg.RegisterServicesFromAssemblyContaining(); cfg.AddOpenBehavior(typeof(LoggingBehavior<,>)); cfg.AddOpenBehavior(typeof(ValidatorBehavior<,>)); cfg.AddOpenBehavior(typeof(TransactionBehavior<,>)); }); // EN: Add FluentValidation / VI: Thêm FluentValidation builder.Services.AddValidatorsFromAssemblyContaining(); // EN: Add API versioning / VI: Thêm API versioning builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; options.ReportApiVersions = true; options.ApiVersionReader = ApiVersionReader.Combine( new UrlSegmentApiVersionReader(), new HeaderApiVersionReader("X-Api-Version")); }) .AddApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; }); // EN: Add controllers / VI: Thêm controllers builder.Services.AddControllers(); // EN: Add ProblemDetails middleware (RFC 7807) / VI: Thêm ProblemDetails middleware builder.Services.AddProblemDetails(options => { options.IncludeExceptionDetails = (ctx, ex) => builder.Environment.IsDevelopment(); }); // EN: Add Swagger / VI: Thêm Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new() { Title = "BookingService API", Version = "v1", Description = "BookingService microservice API / API microservice BookingService" }); }); // EN: Add health checks / VI: Thêm health checks builder.Services.AddHealthChecks() .AddNpgSql( builder.Configuration.GetConnectionString("DefaultConnection") ?? builder.Configuration["DATABASE_URL"] ?? "", name: "postgresql", tags: ["db", "postgresql"]); // EN: Add JWT Bearer authentication via IAM IdentityServer OIDC discovery // VI: Thêm JWT Bearer authentication qua IAM IdentityServer OIDC discovery var jwtAuthority = builder.Configuration["Jwt:Authority"] ?? "http://localhost:5001"; builder.Services.AddAuthentication(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = jwtAuthority; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, }; }); builder.Services.AddAuthorization(); // EN: Add CORS / VI: Thêm CORS builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); var app = builder.Build(); // EN: Configure middleware pipeline / VI: Cấu hình middleware pipeline app.UseSerilogRequestLogging(); app.UseProblemDetails(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "BookingService API v1"); c.RoutePrefix = "swagger"; }); } app.UseCors(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // EN: Map health check endpoints / VI: Map health check endpoints app.MapHealthChecks("/health"); app.MapHealthChecks("/health/live", new() { Predicate = _ => false // EN: Just checks app is running / VI: Chỉ kiểm tra app đang chạy }); app.MapHealthChecks("/health/ready"); // EN: Map controllers / VI: Map controllers app.MapControllers(); // EN: Run the application / VI: Chạy ứng dụng // EN: Auto-apply EF Core migrations on startup // VI: Tự động áp dụng EF Core migrations khi khởi động using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService(); await dbContext.Database.MigrateAsync(); } app.Run(); } catch (Exception ex) { Log.Fatal(ex, "Application terminated unexpectedly / Ứng dụng kết thúc bất ngờ"); throw; } finally { Log.CloseAndFlush(); } // EN: Make Program class accessible for integration tests // VI: Làm cho class Program có thể truy cập cho integration tests public partial class Program { }