src/Microsoft.Azure.SignalR/DependencyInjectionExtensions.cs (81 lines of code) (raw):

// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; #if !NETSTANDARD2_0 using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Routing; #endif using Microsoft.AspNetCore.SignalR; using Microsoft.Azure.SignalR; using Microsoft.Azure.SignalR.Protocol; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.DependencyInjection; /// <summary> /// Extension methods for <see cref="ISignalRServerBuilder"/>. /// </summary> public static class AzureSignalRDependencyInjectionExtensions { /// <summary> /// Adds the minimum essential Azure SignalR services to the specified <see cref="ISignalRServerBuilder" />. /// </summary> /// <param name="builder">The <see cref="ISignalRServerBuilder"/>.</param> /// <returns>The same instance of the <see cref="ISignalRServerBuilder"/> for chaining.</returns> /// <remarks> /// It reads connection string from a configuration entry Azure:SignalR:ConnectionString. /// In development environment, try `dotnet user-secrets set Azure:SignalR:ConnectionString {YourConnectionString}`. /// </remarks> public static ISignalRServerBuilder AddAzureSignalR(this ISignalRServerBuilder builder) { return builder.AddAzureSignalR<ServiceOptionsSetup>(); } /// <summary> /// Add Azure SignalR with specified name, the connection string will be read from ConnectionStrings_{name}, the settings are loaded from Azure:SignalR:{name} section /// </summary> /// <param name="builder">The <see cref="ISignalRServerBuilder"/>.</param> /// <param name="name">The name of the Azure SignalR service that settings and connection strings are read from</param> /// <returns>The same instance of the <see cref="ISignalRServerBuilder"/> for chaining.</returns> public static ISignalRServerBuilder AddNamedAzureSignalR(this ISignalRServerBuilder builder, string name) { if (string.IsNullOrEmpty(name)) { throw name == null ? new ArgumentNullException(nameof(name)) : new ArgumentException("The value cannot be an empty string.", nameof(name)); } builder.Services.SetupOptions<ServiceOptions, ServiceOptionsSetup>(s => ActivatorUtilities.CreateInstance<ServiceOptionsSetup>(s, name)); return builder.AddAzureSignalRCore(); } /// <summary> /// Adds the minimum essential Azure SignalR services to the specified <see cref="ISignalRServerBuilder" />. /// </summary> /// <param name="builder">The <see cref="ISignalRServerBuilder"/>.</param> /// <param name="connectionString">The connection string of an Azure SignalR Service instance.</param> /// <returns>The same instance of the <see cref="ISignalRServerBuilder"/> for chaining.</returns> public static ISignalRServerBuilder AddAzureSignalR(this ISignalRServerBuilder builder, string connectionString) { return builder.AddAzureSignalR(options => { options.ConnectionString = connectionString; }); } /// <summary> /// Adds the minimum essential Azure SignalR services to the specified <see cref="ISignalRServerBuilder" />. /// </summary> /// <param name="builder">The <see cref="ISignalRServerBuilder"/>.</param> /// <param name="configure">A callback to configure the <see cref="ServiceOptions"/>.</param> /// <returns>The same instance of the <see cref="ISignalRServerBuilder"/> for chaining.</returns> public static ISignalRServerBuilder AddAzureSignalR(this ISignalRServerBuilder builder, Action<ServiceOptions> configure) { builder.AddAzureSignalR() .Services.Configure(configure); return builder; } /// <typeparam name="TOptionsSetup">The set up class used to configure <see cref="ServiceOptions"/> and track changes.</typeparam> internal static ISignalRServerBuilder AddAzureSignalR<TOptionsSetup>(this ISignalRServerBuilder builder) where TOptionsSetup : class, IConfigureOptions<ServiceOptions>, IOptionsChangeTokenSource<ServiceOptions> { builder.Services.SetupOptions<ServiceOptions, TOptionsSetup>(); return builder.AddAzureSignalRCore(); } private static ISignalRServerBuilder AddAzureSignalRCore(this ISignalRServerBuilder builder) { builder.Services .PostConfigure<ServiceOptions>(o => o.Validate()) .AddSingleton(typeof(HubLifetimeManager<>), typeof(ServiceLifetimeManager<>)) .AddSingleton(typeof(IServiceProtocol), typeof(ServiceProtocol)) .AddSingleton(typeof(IClientConnectionManager), typeof(ClientConnectionManager)) .AddSingleton(typeof(IServiceConnectionManager<>), typeof(ServiceConnectionManager<>)) .AddSingleton(typeof(IServiceEndpointManager), typeof(ServiceEndpointManager)) .AddSingleton(typeof(IServerNameProvider), typeof(DefaultServerNameProvider)) .AddSingleton(typeof(IBlazorDetector), typeof(DefaultBlazorDetector)) .AddSingleton(typeof(IConnectionFactory), typeof(ConnectionFactory)) .AddSingleton(typeof(ICultureFeatureManager), typeof(DefaultCultureFeatureManager)) .AddSingleton(typeof(ServiceHubDispatcher<>)) .AddSingleton(typeof(ServerLifetimeManager)) .AddSingleton(typeof(AzureSignalRMarkerService)) .AddSingleton<IClientConnectionFactory, ClientConnectionFactory>() .AddSingleton<IHostedService, HeartBeat>() .AddSingleton(typeof(NegotiateHandler<>)); // If a custom router is added, do not add the default router builder.Services.TryAddSingleton(typeof(IEndpointRouter), typeof(DefaultEndpointRouter)); builder.Services.TryAddSingleton(typeof(IConnectionRequestIdProvider), typeof(DefaultConnectionRequestIdProvider)); // If a custom service event handler is added, do not add the default handler. builder.Services.TryAddSingleton<IServiceEventHandler, DefaultServiceEventHandler>(); // IEndpointRouter and IAccessKeySynchronizer is required to build ClientInvocationManager. builder.Services #if NET7_0_OR_GREATER .AddSingleton<IClientInvocationManager, ClientInvocationManager>(); #else .AddSingleton<IClientInvocationManager, DummyClientInvocationManager>(); #endif #if !NETSTANDARD2_0 builder.Services.TryAddSingleton<AzureSignalRHostedService>(); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IStartupFilter, AzureSignalRStartupFilter>()); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<MatcherPolicy, NegotiateMatcherPolicy>()); #endif return builder; } }