FruitBankHybridApp/FruitBankHybrid.Web/Program.cs

100 lines
4.3 KiB
C#

using AyCode.Core.Loggers;
using AyCode.Core.Serializers.Binaries;
using AyCode.Services.SignalRs;
using FruitBank.Common;
using FruitBank.Common.Models;
using FruitBank.Common.Services;
using FruitBank.Common.Server.Services.Loggers;
using FruitBankHybrid.Shared.Databases;
using FruitBankHybrid.Shared.Services;
using FruitBankHybrid.Shared.Services.Loggers;
using FruitBankHybrid.Shared.Services.SignalRs;
using FruitBankHybrid.Web.Components;
using FruitBankHybrid.Web.Services;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents().AddInteractiveWebAssemblyComponents();
builder.Services.AddDevExpressBlazor(configure => configure.SizeMode = DevExpress.Blazor.SizeMode.Medium);
builder.Services.AddMvc();
builder.Services.AddSingleton<IFormFactor, FormFactor>();
builder.Services.AddSingleton<ISecureCredentialService, ServerSecureCredentialService>();
builder.Services.AddSingleton<IAcLogWriterBase, ConsoleLogWriter>();
// Logger options + framework factory. LoggerClient instances are created per caller category,
// with AppType+LogLevel from appsettings and writers resolved from DI via IAcLogWriterBase.
builder.Services.Configure<AcLoggerOptions>(builder.Configuration.GetSection("AyCode:Logger"));
builder.Services.AddAcLoggerFactory<LoggerClient>();
builder.Services.AddSingleton<LoggedInModel>(sp => new LoggedInModel(sp.GetRequiredService<ISecureCredentialService>()));
// Bind SignalR options from appsettings.json — single Configure call per options type.
// The lambda runs the appsettings Bind first, then any runtime overrides (e.g. the WASM safety net).
builder.Services.Configure<AcHubConnectionOptions>(opts => builder.Configuration.GetSection("AcHubConnection").Bind(opts));
builder.Services.Configure<AcBinaryHubProtocolOptions>(opts =>
{
builder.Configuration.GetSection("AcBinaryHubProtocol").Bind(opts);
// Platform safety net: on WebAssembly the AsyncSegment send-path is unsupported
// (Validate() would throw). No-op on this server host, but matches the contract.
if (OperatingSystem.IsBrowser() && opts.ProtocolMode == BinaryProtocolMode.AsyncSegment)
opts.ProtocolMode = BinaryProtocolMode.Segment;
});
// HubConnectionBuilder — transient so each consumer gets a fresh builder to Build().
// All connection and protocol configuration flows from appsettings.json via IOptions<T>;
// AddAcDefaults (framework) applies AcHubConnectionOptions and bridges the provided logger into SignalR's internal pipeline.
// NOTE: AcBinaryHubProtocolOptions is resolved from the OUTER service provider and passed
// explicitly — HubConnectionBuilder's inner DI cannot see outer services.Configure<T>() registrations.
builder.Services.AddTransient<IHubConnectionBuilder>(sp =>
{
var loggerFactory = sp.GetRequiredService<Func<string, LoggerClient>>();
var connectionOpts = sp.GetRequiredService<IOptions<AcHubConnectionOptions>>().Value;
var protocolOpts = sp.GetRequiredService<IOptions<AcBinaryHubProtocolOptions>>().Value;
var logger = loggerFactory(nameof(FruitBankSignalRClient));
var hubBuilder = new HubConnectionBuilder().AddAcDefaults(logger, connectionOpts);
hubBuilder.AddAcBinaryProtocol(protocolOpts);
return hubBuilder;
});
builder.Services.AddSingleton<FruitBankSignalRClient>();
builder.Services.AddSingleton<DatabaseClient>();
//builder.Services.AddScoped<LoggerToLoggerApiController>();
//builder.Services.AddSingleton<SessionService>();
//builder.Services.AddScoped<IFruitBankDataControllerServer, FruitBankDataController>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
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.MapStaticAssets();
app.MapRazorComponents<App>()
//.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(FruitBankHybrid.Shared._Imports).Assembly, typeof(FruitBankHybrid.Web.Client._Imports).Assembly);
app.Run();