/// /// EN: ASP.NET Core BFF (Backend for Frontend) with YARP Reverse Proxy. /// VI: ASP.NET Core BFF (Backend for Frontend) với YARP Reverse Proxy. /// using Microsoft.AspNetCore.Rewrite; var builder = WebApplication.CreateBuilder(args); // ═══════════════════════════════════════════════════════════════════════════════ // EN: Add services to the container // VI: Thêm các services vào container // ═══════════════════════════════════════════════════════════════════════════════ // EN: Load YARP configuration from yarp.json // VI: Load cấu hình YARP từ yarp.json builder.Configuration.AddJsonFile("yarp.json", optional: false, reloadOnChange: true); // EN: Add YARP Reverse Proxy // VI: Thêm YARP Reverse Proxy builder.Services.AddReverseProxy() .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy")); // EN: Add OpenAPI/Swagger support // VI: Thêm hỗ trợ OpenAPI/Swagger builder.Services.AddOpenApi(); // EN: Add CORS for Blazor WebAssembly client // VI: Thêm CORS cho Blazor WebAssembly client builder.Services.AddCors(options => { options.AddPolicy("BlazorClient", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); // EN: Add health checks // VI: Thêm health checks builder.Services.AddHealthChecks(); // EN: Add MVC controllers for BFF data endpoints // VI: Thêm MVC controllers cho BFF data endpoints builder.Services.AddControllers(); var app = builder.Build(); // ═══════════════════════════════════════════════════════════════════════════════ // EN: Configure the HTTP request pipeline // VI: Cấu hình HTTP request pipeline // ═══════════════════════════════════════════════════════════════════════════════ if (app.Environment.IsDevelopment()) { app.MapOpenApi(); app.UseDeveloperExceptionPage(); app.UseWebAssemblyDebugging(); } app.UseHttpsRedirection(); // EN: Enable CORS // VI: Kích hoạt CORS app.UseCors("BlazorClient"); // EN: Rewrite localized framework/content requests to root // VI: Viết lại các yêu cầu framework/content từ đường dẫn ngôn ngữ về root var rewriteOptions = new RewriteOptions() .AddRewrite(@"^(en-US|vi-VN)/(_framework|_content)/(.*)", "$2/$3", skipRemainingRules: true); app.UseRewriter(rewriteOptions); // EN: Serve static files with fingerprinting support (.NET 10+) // VI: Phục vụ static files với hỗ trợ fingerprinting (.NET 10+) app.MapStaticAssets(); // EN: Map health check endpoint // VI: Map endpoint health check app.MapHealthChecks("/health"); // EN: Map YARP Reverse Proxy routes to microservices // VI: Map các routes YARP Reverse Proxy đến microservices app.MapReverseProxy(); // EN: Localization Support - Serve index.html with dynamic base tag for specific cultures // VI: Hỗ trợ đa ngôn ngữ - Phục vụ index.html với base tag động cho các ngôn ngữ cụ thể var supportedCultures = new[] { "en-US", "vi-VN" }; var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture("en-US") .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions); // Handle mapped culture routes (e.g. /en-US/home, /vi-VN/solutions) app.Map("{culture:regex(^(en-US|vi-VN)$)}/{**slug}", async (string culture, HttpContext context, IWebHostEnvironment env) => { // Try to find index.html var fileInfo = env.WebRootFileProvider.GetFileInfo("index.html"); if (!fileInfo.Exists) { // In Development with Hosted Blazor, index.html might not be in Server's wwwroot strictly directly depending on setup, // but typically it is served via StaticFiles/BlazorFrameworkFiles. // If we can't find it easily via IWebHostEnvironment in Dev, we might fail. // However, for this task let's assume standard structure or handle gracefully. return Results.NotFound("index.html not found in wwwroot. Ensure the Client project is built."); } using var stream = fileInfo.CreateReadStream(); using var reader = new StreamReader(stream); var html = await reader.ReadToEndAsync(); // Replace base tag: -> // Be robust with spaces or standard format var modifiedHtml = html.Replace("", $"") .Replace("", $""); return Results.Content(modifiedHtml, "text/html"); }); // EN: Map BFF API controllers // VI: Map BFF API controllers app.MapControllers(); // EN: Fallback to index.html for SPA routing (default culture) // VI: Fallback đến index.html cho SPA routing (ngôn ngữ mặc định) app.MapFallbackToFile("index.html"); app.Run();