using CPRNIMS.Domain.UIContracts.Account; using CPRNIMS.Domain.UIContracts.Canvass; using CPRNIMS.Domain.UIContracts.CaptCha; using CPRNIMS.Domain.UIContracts.Common; using CPRNIMS.Domain.UIContracts.Finance; using CPRNIMS.Domain.UIContracts.Inventory; using CPRNIMS.Domain.UIContracts.Items; using CPRNIMS.Domain.UIContracts.PO; using CPRNIMS.Domain.UIContracts.PR; using CPRNIMS.Domain.UIContracts.Receiving; using CPRNIMS.Domain.UIContracts.SMTP; using CPRNIMS.Domain.UIServices.Account; using CPRNIMS.Domain.UIServices.Canvass; using CPRNIMS.Domain.UIServices.CaptCha; using CPRNIMS.Domain.UIServices.Common; using CPRNIMS.Domain.UIServices.Finance; using CPRNIMS.Domain.UIServices.Inventory; using CPRNIMS.Domain.UIServices.Items; using CPRNIMS.Domain.UIServices.PO; using CPRNIMS.Domain.UIServices.PR; using CPRNIMS.Domain.UIServices.Receiving; using CPRNIMS.Domain.UIServices.SMTP; using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Helper; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http.Features; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; namespace CPRNIMS.WebApps.Common { public static class ServiceExtensions { public static void AddApplicationServices(this IServiceCollection services, WebApplicationBuilder builder) { ConfigureHttpClient(builder); AddScopedServices(builder); AddSessionAndAuthentication(builder); AddDbContext(builder); FileSizeHelper(builder); CacheUpdater(services); } private static void CacheUpdater(IServiceCollection services) { services.AddControllersWithViews().AddRazorRuntimeCompilation(); services.AddSignalR(); } private static void FileSizeHelper(WebApplicationBuilder builder) { builder.Services.Configure(options => { options.ValueCountLimit = int.MaxValue; options.MultipartBodyLengthLimit = long.MaxValue; options.MemoryBufferThreshold = int.MaxValue; }); } private static void ConfigureHttpClient(WebApplicationBuilder builder) { builder.Services.AddHttpClient(client => { client.BaseAddress = new Uri(builder.Configuration["CommonEndpoints:ApiDefaultHeaders:BaseUrl"]); //This code block should be removed once deployed in production }).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true }); } private static void AddScopedServices(WebApplicationBuilder builder) { builder.Services.AddTransient(); builder.Services.AddScoped(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddScoped(); } private static void AddSessionAndAuthentication(WebApplicationBuilder builder) { // Configure Session with sliding expiration builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromHours(2); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; options.Cookie.SameSite = SameSiteMode.Lax; // or Strict for better security }); // Configure Authentication with sliding expiration builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/Home/Index"; options.LogoutPath = "/Home/Logout"; options.AccessDeniedPath = "/Home/AccessDenied"; // CRITICAL: Enable sliding expiration options.SlidingExpiration = true; // Set expiration time to match your session timeout options.ExpireTimeSpan = TimeSpan.FromHours(2); // Cookie configuration for security options.Cookie.HttpOnly = true; //options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // Requires HTTPS options.Cookie.SameSite = SameSiteMode.Lax; options.Cookie.IsEssential = true; // Optional: Cookie name customization // options.Cookie.Name = ".MyApp.Auth"; // Optional: Handle cookie expiration events options.Events = new CookieAuthenticationEvents { OnValidatePrincipal = async context => { // Log when cookie is validated (useful for debugging) var lastChanged = context.Properties.IssuedUtc; var currentUtc = DateTimeOffset.UtcNow; var timeElapsed = currentUtc.Subtract(lastChanged.Value); await Task.CompletedTask; }, OnRedirectToLogin = context => { // Handle session timeout redirect if (context.Request.Path.StartsWithSegments("/api")) { // For API calls, return 401 instead of redirect context.Response.StatusCode = StatusCodes.Status401Unauthorized; } else { // For regular pages, redirect to login context.Response.Redirect(context.RedirectUri); } return Task.CompletedTask; } }; }); } private static void AddDbContext(WebApplicationBuilder builder) { builder.Services.AddDbContext(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); } } }