using ChapterX.Application; using ChapterX.Infrastructure; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Reflection; using System.Text; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy("Frontend", policy => policy.WithOrigins("http://localhost:5173", "https://localhost:5173") .AllowAnyHeader() .AllowAnyMethod()); }); builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles; }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.CustomSchemaIds(type => type.FullName); options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme { Name = "Authorization", Type = Microsoft.OpenApi.Models.SecuritySchemeType.Http, Scheme = "Bearer", BearerFormat = "JWT", In = Microsoft.OpenApi.Models.ParameterLocation.Header, Description = "Enter your JWT token" }); options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement { { new Microsoft.OpenApi.Models.OpenApiSecurityScheme { Reference = new Microsoft.OpenApi.Models.OpenApiReference { Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme, Id = "Bearer" } }, Array.Empty() } }); }); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)) }; }); builder.Services.AddAuthorization(); builder.Services.AddApplication(); builder.Services.AddInfrastructure(builder.Configuration); var app = builder.Build(); app.UseCors("Frontend"); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseExceptionHandler(err => err.Run(async ctx => { var ex = ctx.Features.Get()?.Error; ctx.Response.ContentType = "application/json"; string message; int status; if (ex is UnauthorizedAccessException) { status = 401; message = ex.Message; } else if (ex is InvalidOperationException) { status = 400; message = ex.Message; } else if (ex is Microsoft.EntityFrameworkCore.DbUpdateException dbEx) { status = 400; var inner = dbEx.InnerException?.Message ?? ""; if (inner.Contains("email_format")) message = "Invalid email format."; else if (inner.Contains("unique") || inner.Contains("duplicate") || inner.Contains("23505")) message = "A user with this email or username already exists."; else message = "Database error: " + inner; } else { status = 500; message = ex?.Message ?? "An error occurred."; } ctx.Response.StatusCode = status; await ctx.Response.WriteAsJsonAsync(new { message }); })); app.UseAuthentication(); app.UseAuthorization(); try { app.MapControllers(); } catch (ReflectionTypeLoadException ex) { Console.Error.WriteLine("ReflectionTypeLoadException while mapping controllers:"); foreach (var loaderEx in ex.LoaderExceptions ?? []) { Console.Error.WriteLine(loaderEx.ToString()); } throw; } app.Run();