using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using ServerManagement.Components; using ServerManagement.Components.Account; using ServerManagement.Data; using ServerManagement.Models; using ServerManagement.StateStore; var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Do not use this, it can cause non-thread-safe complications, due to its Scoped lifetime. // builder.Services.AddDbContext(); // Instead, use factory: builder.Services.AddDbContextFactory( options => { options.UseSqlite(builder.Configuration.GetConnectionString("ServerManagement")); } ); builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); // Provides server interactivity. // Singleton - A single instance is created and shared troughout the application's lifetime. // Scoped - A new instance is created for each request. // Transient - A new instance is created every time it is needed. // See: https://www.youtube.com/watch?v=V-8HlozCTOU builder.Services.AddTransient(); // Scoped lifespan is the same as the SignalR lifespan. // Everything stored in the SignalR channel will be lost if that connection is broken. // This means that the data in there, can only be used for the current user. // For a WebAssembly, you want to use AddSingleton, so that everything is locally downloaded in the browser. builder.Services.AddScoped(); builder.Services.AddScoped(); // Transient is used here, the database is already globally accessible, // so this service does not need to live longer than necessary, just when needed. // First the interface is registered, then its concrete implementation. builder.Services.AddTransient(); // Add Identity services. builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddIdentityCookies(); var connectionString = builder.Configuration.GetConnectionString("ServerManagement") ?? throw new InvalidOperationException("Connection string 'ServerManagement' not found."); builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddIdentityCore(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores() .AddSignInManager() .AddDefaultTokenProviders(); builder.Services.AddSingleton, IdentityNoOpEmailSender>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAntiforgery(); app.MapRazorComponents() .AddInteractiveServerRenderMode(); // Provides server interactivity. app.Run();