using System.Text; using System.Text.Json.Serialization; using Asp.Versioning; using General_Ledger_Service.Infra; using General_Ledger_Service.Infra.UoW; using General_Ledger_Service.Interfaces.Repositories; using General_Ledger_Service.Interfaces.Services; using General_Ledger_Service.Middleware; using General_Ledger_Service.Repositories; using General_Ledger_Service.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; QuestPDF.Settings.License = QuestPDF.Infrastructure.LicenseType.Community; var builder = WebApplication.CreateBuilder(args); // Add services to the container. // IgnoreCycles: several models have bidirectional parent/collection navigation // (JournalEntry<->JournalEntryLine now; FixedAsset/Budget/RecurringJournalTemplate/ // BankAccount and their line/child tables later) - without this, returning a parent // with an `Include`d collection throws a JSON serialization cycle error. builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; }); // API versioning builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; options.ApiVersionReader = new UrlSegmentApiVersionReader(); }).AddMvc(); // OpenAPI / Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Database builder.Services.AddDbContext(options => { var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); // AutoDetect so the same build works against MySQL 8 (deployed) and MariaDB (local XAMPP). options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); }); // Unit of Work builder.Services.AddScoped(); // Repositories builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Health checks builder.Services.AddHealthChecks() .AddDbContextCheck(); // Authentication var jwtSection = builder.Configuration.GetSection("Jwt"); var signingKey = jwtSection["SigningKey"]; if (!string.IsNullOrWhiteSpace(signingKey)) { builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSection["Issuer"], ValidAudience = jwtSection["Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signingKey)) }; }); } builder.Services.AddAuthorization(); var app = builder.Build(); // Configure the HTTP request pipeline. app.UseMiddleware(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseMiddleware(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.MapHealthChecks("/health"); app.Run();