Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/ServiceCollectionExtensions.cs
T

90 lines
4.6 KiB
C#

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.ScadaBridge.CentralUI.Auth;
using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared;
using ZB.MOM.WW.ScadaBridge.CentralUI.ScriptAnalysis;
using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
using ZB.MOM.WW.ScadaBridge.KpiHistory;
namespace ZB.MOM.WW.ScadaBridge.CentralUI;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Registers all Central UI services including Blazor, auth state, dialogs, audit query, and script analysis.
/// </summary>
/// <param name="services">The service collection to configure.</param>
/// <returns>The <paramref name="services"/> instance for chaining.</returns>
public static IServiceCollection AddCentralUI(this IServiceCollection services)
{
services.AddRazorComponents()
.AddInteractiveServerComponents();
services.AddHttpContextAccessor();
services.AddScoped<AuthenticationStateProvider, CookieAuthenticationStateProvider>();
services.AddCascadingAuthenticationState();
// Resolves the current user's permitted site set from their SiteId claims
// so Deployment/Monitoring pages can enforce site scoping (CentralUI-002).
services.AddScoped<SiteScopeService>();
// Centralised dialog service: pages inject IDialogService and a single
// <DialogHost /> in MainLayout renders the active dialog. See
// Components/Shared/IDialogService.cs.
services.AddScoped<IDialogService, DialogService>();
// Audit Log (#23 M7-T3): CentralUI facade over IAuditLogRepository so the
// results grid can be tested with a stubbed query source.
//
// Registered with an explicit factory so the IServiceScopeFactory ctor is
// always chosen — AuditLogQueryService has a second (test-seam) ctor that
// takes IAuditLogRepository directly, and both are constructor-resolvable,
// so default activation would be ambiguous. The scope-factory ctor opens a
// fresh DbContext per query, which is what keeps the page's auto-load from
// racing AuditFilterBar's site enumeration on the shared scoped context.
services.AddScoped<IAuditLogQueryService>(sp => new AuditLogQueryService(
sp.GetRequiredService<IServiceScopeFactory>(),
sp.GetRequiredService<ICentralHealthAggregator>()));
// Audit Log (#23 M7-T14 / Bundle F): server-side streaming CSV export.
// Backs the Audit Log page's Export button via GET /api/centralui/audit/export.
services.AddScoped<IAuditLogExportService, AuditLogExportService>();
// KPI History (M6, K11): CentralUI facade over IKpiHistoryRepository that
// fetches a raw series and reduces it with KpiSeriesBucketer for the trend chart.
//
// Registered with an explicit factory so the IServiceScopeFactory ctor is
// always chosen — KpiHistoryQueryService has a second (test-seam) ctor that
// takes IKpiHistoryRepository directly, and both are constructor-resolvable,
// so default activation would be ambiguous. The scope-factory ctor opens a
// fresh DbContext per query, mirroring AuditLogQueryService so a chart's
// auto-load never races other reads on the shared circuit-scoped context.
services.AddScoped<IKpiHistoryQueryService>(sp => new KpiHistoryQueryService(
sp.GetRequiredService<IServiceScopeFactory>(),
sp.GetRequiredService<IOptions<KpiHistoryOptions>>()));
// OPC UA Tag Browser (Task 14): facade over CommunicationService.BrowseNodeAsync
// that enforces the CentralUI-side Design-role trust boundary and translates
// transport failures into typed BrowseFailure results for the dialog.
services.AddScoped<IBrowseService, BrowseService>();
// Test Bindings: facade over CommunicationService.ReadTagValuesAsync —
// same Design-role guard + typed-failure translation as the browse
// service. Backs the Test Bindings dialog on the Configure Instance
// page (one-shot live read of every bound attribute, grouped by
// connection).
services.AddScoped<IBindingTester, BindingTester>();
// Roslyn-backed C# analysis for the Monaco script editor.
// Scoped because SharedScriptCatalog wraps a scoped service.
services.AddMemoryCache(o => o.SizeLimit = 200);
services.AddScoped<ISharedScriptCatalog, SharedScriptCatalog>();
services.AddScoped<ScriptAnalysisService>();
return services;
}
}