using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using System.Text; using System.Text.Json.Serialization; using vendorApproverBackend.Data; using vendorApproverBackend.Data.Seed; using vendorApproverBackend.Services; using vendorApproverBackend.Interfaces; using Microsoft.AspNetCore.HttpOverrides; using vendorApproverBackend.Settings; using vendorApproverBackend.Hubs; using Npgsql; // ADD THIS IMPORT AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); var builder = WebApplication.CreateBuilder(args); builder.Services.Configure(builder.Configuration.GetSection("SmtpSettings")); // *** UPDATED DbContext Configuration with EnableDynamicJson *** var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext(options => { var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString); dataSourceBuilder.EnableDynamicJson(); // CRITICAL: Enable dynamic JSON serialization var dataSource = dataSourceBuilder.Build(); options.UseNpgsql(dataSource); }); builder.Services.AddSignalR(options => { options.EnableDetailedErrors = true; options.MaximumReceiveMessageSize = 102400; }); // Add HttpClient for Azure Graph API builder.Services.AddHttpClient(); 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.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); 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.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); builder.Services.AddCors(options => { options.AddPolicy("CorsPolicy", policy => { policy.WithOrigins( "http://localhost:4200", "https://localhost:4200", "https://productapproval.rooted.om", "https://www.productapproval.rooted.om" ) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); 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"])) }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/notificationHub")) { context.Token = accessToken; Console.WriteLine("SignalR: JWT token received via query string"); } return Task.CompletedTask; }, OnAuthenticationFailed = context => { Console.WriteLine($"SignalR Authentication failed: {context.Exception.Message}"); return Task.CompletedTask; } }; }); builder.Services.AddAuthorization(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Name = "Authorization", Type = SecuritySchemeType.Http, Scheme = "Bearer", BearerFormat = "JWT", In = ParameterLocation.Header, Description = "JWT Authorization header using the Bearer scheme." }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] {} } }); }); var app = builder.Build(); await app.InitializeDbAsync(); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); app.UseCors("CorsPolicy"); app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthentication(); app.UseStaticFiles(); app.UseAuthorization(); app.MapHub("/notificationHub"); app.MapGet("/notificationHub/health", () => Results.Ok(new { status = "SignalR Hub is running" })); app.MapControllers(); app.Run();