using System.Text.Encodings.Web; using System.Text.Json.Serialization; using System.Text.Unicode; using Kemkas.Web.Config; using Kemkas.Web.Db; using Kemkas.Web.Db.Models; using Kemkas.Web.Services.FirstEdition.Character; using Kemkas.Web.Services.Identity; using Kemkas.Web.Services.SecondEdition.Character; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.EntityFrameworkCore; // using OpenTelemetry.Metrics; // using OpenTelemetry.Resources; // using OpenTelemetry.Trace; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure(builder.Configuration.GetSection(MailgunOptions.Section)); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext( options => options.UseNpgsql(connectionString)); builder.Services.AddDataProtection() .SetApplicationName("kemkas") .PersistKeysToDbContext(); builder.Services.AddHttpClient(); builder.Services.AddSingleton(); builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores(); builder.AddAuth(); builder.Services.AddControllersWithViews().AddJsonOptions(options => { options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; options.JsonSerializerOptions.AllowTrailingCommas = true; options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); }); builder.Services.AddRazorPages(); builder.AddOpenTelemetry(); builder.Services.AddHealthChecks(); builder.Services.AddCharacter1EServices(); builder.Services.AddCharacter2EServices(); // Configure the HTTP request pipeline. var app = builder.Build(); app.UsePathBase("/api"); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedForHeaderName = "X-Forwarded-For", ForwardedHostHeaderName = "X-Forwarded-Host", ForwardedProtoHeaderName = "X-Forwarded-Proto", ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto, KnownIPNetworks = { System.Net.IPNetwork.Parse("0.0.0.0/0") } }); if (app.Environment.IsDevelopment()) { app.UseMigrationsEndPoint(); app.UseDeveloperExceptionPage(); } else { // Force HTTPS because prod environment is behind unmanaged proxy. app.Use((context, next) => { context.Request.Scheme = "https"; return next(context); }); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); // TODO: check if this should be handled by proxy } app.UseHealthChecks("/health"); await using (var scope = app.Services.CreateAsyncScope()) { var db = scope.ServiceProvider.GetRequiredService(); await db.Database.MigrateAsync(); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "/{controller}/{action=Index}/{id?}"); app.MapRazorPages(); app.MapFallbackToFile("index.html"); app.Run();