| File: DependencyInjection\ComponentServiceCollectionExtensions.cs | Web Access |
| Project: src\aspnetcore\src\Components\Server\src\Microsoft.AspNetCore.Components.Server.csproj (Microsoft.AspNetCore.Components.Server) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Endpoints; using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.Components.Server; using Microsoft.AspNetCore.Components.Server.BlazorPack; using Microsoft.AspNetCore.Components.Server.Circuits; using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.SignalR.Protocol; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.JSInterop; namespace Microsoft.Extensions.DependencyInjection; /// <summary> /// Extension methods to configure an <see cref="IServiceCollection"/> for components. /// </summary> public static class ComponentServiceCollectionExtensions { /// <summary> /// Adds Server-Side Blazor services to the service collection. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/>.</param> /// <param name="configure">A callback to configure <see cref="CircuitOptions"/>.</param> /// <returns>An <see cref="IServerSideBlazorBuilder"/> that can be used to further customize the configuration.</returns> [RequiresUnreferencedCode("Server-side Blazor does not currently support trimming or native AOT.", Url = "https://aka.ms/aspnet/trimming")] public static IServerSideBlazorBuilder AddServerSideBlazor(this IServiceCollection services, Action<CircuitOptions>? configure = null) { var builder = new DefaultServerSideBlazorBuilder(services); services.AddDataProtection(); services.TryAddScoped<ProtectedLocalStorage>(); services.TryAddScoped<ProtectedSessionStorage>(); // This call INTENTIONALLY uses the AddHubOptions on the SignalR builder, because it will merge // the global HubOptions before running the configure callback. We want to ensure that happens // once. Our AddHubOptions method doesn't do this. // // We need to restrict the set of protocols used by default to our specialized one. Users have // the chance to modify options further via the builder. // // Other than the options, the things exposed by the SignalR builder aren't very meaningful in // the Server-Side Blazor context and thus aren't exposed. services.AddSignalR().AddHubOptions<ComponentHub>(options => { options.SupportedProtocols.Clear(); options.SupportedProtocols.Add(BlazorPackHubProtocol.ProtocolName); }); // Register the Blazor specific hub protocol services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, BlazorPackHubProtocol>()); // Here we add a bunch of services that don't vary in any way based on the // user's configuration. So even if the user has multiple independent server-side // Components entrypoints, this lot is the same and repeated registrations are a no-op. services.TryAddSingleton<CircuitMetrics>(); services.TryAddSingleton<ICircuitFactory, CircuitFactory>(); services.TryAddSingleton<ICircuitHandleRegistry, CircuitHandleRegistry>(); services.TryAddSingleton<RootTypeCache>(); services.TryAddSingleton<ComponentParameterDeserializer>(); services.TryAddSingleton<ComponentParametersTypeCache>(); services.TryAddSingleton<CircuitIdFactory>(); services.TryAddSingleton<ServerComponentSerializer>(); services.TryAddScoped<IServerComponentDeserializer, ServerComponentDeserializer>(); services.TryAddScoped<IErrorBoundaryLogger, RemoteErrorBoundaryLogger>(); services.TryAddScoped<AntiforgeryStateProvider, DefaultAntiforgeryStateProvider>(); services.TryAddScoped(s => s.GetRequiredService<ICircuitAccessor>().Circuit); services.TryAddScoped<ICircuitAccessor, DefaultCircuitAccessor>(); services.TryAddSingleton<ISystemClock, SystemClock>(); services.TryAddSingleton<CircuitRegistry>(); services.TryAddSingleton<CircuitPersistenceManager>(); // Register the circuit persistence provider conditionally based on HybridCache availability services.TryAddSingleton<ICircuitPersistenceProvider>(serviceProvider => { var circuitOptions = serviceProvider.GetRequiredService<IOptions<CircuitOptions>>(); if (circuitOptions.Value.HybridPersistenceCache is not null) { var logger = serviceProvider.GetRequiredService<ILogger<ICircuitPersistenceProvider>>(); return new HybridCacheCircuitPersistenceProvider(circuitOptions.Value.HybridPersistenceCache, logger, circuitOptions); } else { var logger = serviceProvider.GetRequiredService<ILogger<ICircuitPersistenceProvider>>(); var clock = serviceProvider.GetRequiredService<ISystemClock>(); return new DefaultInMemoryCircuitPersistenceProvider(clock, logger, circuitOptions); } }); // Register the configurator for HybridCache services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CircuitOptions>, DefaultHybridCache>()); // Standard blazor hosting services implementations // // These intentionally replace the non-interactive versions included in MVC. services.AddScoped<NavigationManager, RemoteNavigationManager>(); services.AddScoped<IJSRuntime, RemoteJSRuntime>(); services.AddScoped<INavigationInterception, RemoteNavigationInterception>(); services.AddScoped<IScrollToLocationHash, RemoteScrollToLocationHash>(); services.TryAddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>(); services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJSInteropDetailedErrorsConfiguration>()); services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJavaScriptInitializersConfiguration>()); services.TryAddScoped<CircuitActivitySource>(); if (configure != null) { services.Configure(configure); } return builder; } private sealed class DefaultServerSideBlazorBuilder : IServerSideBlazorBuilder { public DefaultServerSideBlazorBuilder(IServiceCollection services) { Services = services; } public IServiceCollection Services { get; } } }