FruitBankHybridApp/FruitBankHybrid.Web.Client/Program.cs

75 lines
3.4 KiB
C#

using AyCode.Core.Loggers;
using AyCode.Core.Serializers.Binaries;
using AyCode.Services.SignalRs;
using FruitBank.Common;
using FruitBank.Common.Loggers;
using FruitBank.Common.Models;
using FruitBank.Common.Services;
using FruitBankHybrid.Shared.Databases;
using FruitBankHybrid.Shared.Services;
using FruitBankHybrid.Shared.Services.Loggers;
using FruitBankHybrid.Shared.Services.SignalRs;
using FruitBankHybrid.Web.Client.Services;
using FruitBankHybrid.Web.Client.Services.Loggers;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Options;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddDevExpressBlazor(configure => configure.SizeMode = DevExpress.Blazor.SizeMode.Medium);
// Add device-specific services used by the FruitBankHybrid.Shared project
builder.Services.AddSingleton<IFormFactor, FormFactor>();
builder.Services.AddSingleton<ISecureCredentialService, WebSecureCredentialService>();
#if DEBUG
builder.Services.AddSingleton<IAcLogWriterClientBase, BrowserConsoleLogWriter>();
#endif
builder.Services.AddSingleton<IAcLogWriterClientBase, SignaRClientLogItemWriter>();
builder.Services.AddSingleton<LoggedInModel>(sp => new LoggedInModel(sp.GetRequiredService<ISecureCredentialService>()));
// Bind SignalR options from wwwroot/appsettings.json (loaded automatically by WebAssemblyHostBuilder) —
// single Configure call per options type, combining section Bind with runtime overrides.
builder.Services.Configure<AcHubConnectionOptions>(opts => builder.Configuration.GetSection("AcHubConnection").Bind(opts));
builder.Services.Configure<AcBinaryHubProtocolOptions>(opts =>
{
builder.Configuration.GetSection("AcBinaryHubProtocol").Bind(opts);
// WASM safety net: AsyncSegment send-path is unsupported here — Validate() would throw.
// Downgrade if appsettings.json accidentally specifies it.
if (opts.ProtocolMode == BinaryProtocolMode.AsyncSegment) opts.ProtocolMode = BinaryProtocolMode.Segment;
});
// Logger factory — thin Logger, DI-singleton writers. Each call yields a fresh LoggerClient
// with the caller's categoryName. Mirrors Microsoft's ILoggerFactory / ILogger<T> pattern.
builder.Services.AddSingleton<Func<string, AcLoggerBase>>(sp => categoryName => new LoggerClient(categoryName, sp.GetServices<IAcLogWriterClientBase>().ToArray()));
// HubConnectionBuilder — transient so each consumer gets a fresh builder to Build().
// All connection and protocol configuration flows from appsettings.json via IOptions<T>;
// AddFruitBankDefaults only bridges the provided logger into SignalR's internal pipeline.
builder.Services.AddTransient<IHubConnectionBuilder>(sp =>
{
var loggerFactory = sp.GetRequiredService<Func<string, AcLoggerBase>>();
var connectionOpts = sp.GetRequiredService<IOptions<AcHubConnectionOptions>>().Value;
var logger = loggerFactory(nameof(FruitBankSignalRClient));
var hubBuilder = new HubConnectionBuilder().AddFruitBankDefaults(logger, connectionOpts);
hubBuilder.AddAcBinaryProtocol(); // IOptions<AcBinaryHubProtocolOptions> from DI
return hubBuilder;
});
builder.Services.AddSingleton<FruitBankSignalRClient>();
builder.Services.AddSingleton<DatabaseClient>();
#if DEBUG
if (FruitBankConstClient.SignalRSerializerDiagnosticLog)
{
//SignalResponseDataMessage.DiagnosticLogger = message => { Console.WriteLine(message); };
}
#endif
await builder.Build().RunAsync();