Fix #9316 Expose Blazor HubOptions
This commit is contained in:
parent
16c01d56e2
commit
b3836954ed
|
|
@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
public static partial class ComponentEndpointRouteBuilderExtensions
|
||||
{
|
||||
public static Microsoft.AspNetCore.Components.Server.ComponentEndpointConventionBuilder MapBlazorHub(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints) { throw null; }
|
||||
public static Microsoft.AspNetCore.Components.Server.ComponentEndpointConventionBuilder MapBlazorHub(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, System.Type type, string selector) { throw null; }
|
||||
public static Microsoft.AspNetCore.Components.Server.ComponentEndpointConventionBuilder MapBlazorHub(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, System.Type componentType, string selector, string path) { throw null; }
|
||||
public static Microsoft.AspNetCore.Components.Server.ComponentEndpointConventionBuilder MapBlazorHub<TComponent>(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string selector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
|
||||
public static Microsoft.AspNetCore.Components.Server.ComponentEndpointConventionBuilder MapBlazorHub<TComponent>(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string selector, string path) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
|
||||
|
|
@ -35,17 +36,6 @@ namespace Microsoft.AspNetCore.Components.Server
|
|||
internal ComponentEndpointConventionBuilder() { }
|
||||
public void Add(System.Action<Microsoft.AspNetCore.Builder.EndpointBuilder> convention) { }
|
||||
}
|
||||
public sealed partial class ComponentHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
{
|
||||
public ComponentHub(System.IServiceProvider services, Microsoft.Extensions.Logging.ILogger<Microsoft.AspNetCore.Components.Server.ComponentHub> logger) { }
|
||||
public static Microsoft.AspNetCore.Http.PathString DefaultPath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public void BeginInvokeDotNetFromJS(string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson) { }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public System.Threading.Tasks.Task<bool> ConnectCircuit(string circuitId) { throw null; }
|
||||
public override System.Threading.Tasks.Task OnDisconnectedAsync(System.Exception exception) { throw null; }
|
||||
public void OnRenderCompleted(long renderId, string errorMessageOrNull) { }
|
||||
public string StartCircuit(string uriAbsolute, string baseUriAbsolute) { throw null; }
|
||||
}
|
||||
public partial class ComponentPrerenderingContext
|
||||
{
|
||||
public ComponentPrerenderingContext() { }
|
||||
|
|
@ -100,6 +90,14 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
public static partial class ComponentServiceCollectionExtensions
|
||||
{
|
||||
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddServerSideBlazor(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; }
|
||||
public static Microsoft.Extensions.DependencyInjection.IServerSideBlazorBuilder AddServerSideBlazor(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; }
|
||||
}
|
||||
public partial interface IServerSideBlazorBuilder
|
||||
{
|
||||
Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; }
|
||||
}
|
||||
public static partial class ServerSizeBlazorBuilderExtensions
|
||||
{
|
||||
public static Microsoft.Extensions.DependencyInjection.IServerSideBlazorBuilder AddHubOptions(this Microsoft.Extensions.DependencyInjection.IServerSideBlazorBuilder builder, System.Action<Microsoft.AspNetCore.SignalR.HubOptions> configure) { throw null; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Server;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
|
|
@ -54,6 +53,37 @@ namespace Microsoft.AspNetCore.Builder
|
|||
return endpoints.MapBlazorHub(typeof(TComponent), selector, ComponentHub.DefaultPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the SignalR <see cref="ComponentHub"/> to the path <see cref="ComponentHub.DefaultPath"/> and associates
|
||||
/// the component <paramref name="type"/> to this hub instance as the given DOM <paramref name="selector"/>.
|
||||
/// </summary>
|
||||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/>.</param>
|
||||
/// <param name="type">The first <see cref="IComponent"/> associated with this <see cref="ComponentHub"/>.</param>
|
||||
/// <param name="selector">The selector for the component.</param>
|
||||
/// <returns>The <see cref="ComponentEndpointConventionBuilder"/>.</returns>
|
||||
public static ComponentEndpointConventionBuilder MapBlazorHub(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
Type type,
|
||||
string selector)
|
||||
{
|
||||
if (endpoints == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(endpoints));
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
if (selector == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selector));
|
||||
}
|
||||
|
||||
return endpoints.MapBlazorHub(type, selector, ComponentHub.DefaultPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the SignalR <see cref="ComponentHub"/> to the path <paramref name="path"/> and associates
|
||||
/// the component <typeparamref name="TComponent"/> to this hub instance as the given DOM <paramref name="selector"/>.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
|||
/// <summary>
|
||||
/// A SignalR hub that accepts connections to an ASP.NET Core Components application.
|
||||
/// </summary>
|
||||
public sealed class ComponentHub : Hub
|
||||
internal sealed class ComponentHub : Hub
|
||||
{
|
||||
private static readonly object CircuitKey = new object();
|
||||
private readonly CircuitFactory _circuitFactory;
|
||||
|
|
|
|||
|
|
@ -19,14 +19,24 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
public static class ComponentServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds Razor Component app services to the service collection.
|
||||
/// Adds Server-Side Blazor services to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/>.</returns>
|
||||
public static IServiceCollection AddServerSideBlazor(this IServiceCollection services)
|
||||
/// <returns>An <see cref="IServerSideBlazorBuilder"/> that can be used to further customize the configuration.</returns>
|
||||
public static IServerSideBlazorBuilder AddServerSideBlazor(this IServiceCollection services)
|
||||
{
|
||||
services.AddSignalR()
|
||||
.AddHubOptions<ComponentHub>(options =>
|
||||
var builder = new DefaultServerSideBlazorBuilder(services);
|
||||
|
||||
// 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);
|
||||
|
|
@ -52,11 +62,23 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.AddScoped<IComponentPrerenderer, CircuitPrerenderer>();
|
||||
|
||||
// Standard razor component services implementations
|
||||
//
|
||||
// These intentionally replace the non-interactive versions included in MVC.
|
||||
services.AddScoped<IUriHelper, RemoteUriHelper>();
|
||||
services.AddScoped<IJSRuntime, RemoteJSRuntime>();
|
||||
services.AddScoped<IComponentContext, RemoteComponentContext>();
|
||||
|
||||
return services;
|
||||
return builder;
|
||||
}
|
||||
|
||||
private class DefaultServerSideBlazorBuilder : IServerSideBlazorBuilder
|
||||
{
|
||||
public DefaultServerSideBlazorBuilder(IServiceCollection services)
|
||||
{
|
||||
Services = services;
|
||||
}
|
||||
|
||||
public IServiceCollection Services { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// A builder that can be used to configure Server-Side Blazor.
|
||||
/// </summary>
|
||||
public interface IServerSideBlazorBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
IServiceCollection Services { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components.Server;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides options for configuring Server-Side Blazor.
|
||||
/// </summary>
|
||||
public static class ServerSizeBlazorBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds hub options for the configuration of the SignalR Hub used by Server-Side Blazor.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IServerSideBlazorBuilder"/>.</param>
|
||||
/// <param name="configure">A callback to configure the hub options.</param>
|
||||
/// <returns>The <see cref="IServerSideBlazorBuilder"/>.</returns>
|
||||
public static IServerSideBlazorBuilder AddHubOptions(this IServerSideBlazorBuilder builder, Action<HubOptions> configure)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (configure != null)
|
||||
{
|
||||
builder.Services.Configure<HubOptions<ComponentHub>>(configure);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components.Server;
|
||||
using Microsoft.AspNetCore.Components.Server.BlazorPack;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public class ComponentServiceCollectionExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddServerSideSignalR_RegistersBlazorPack()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddServerSideBlazor();
|
||||
|
||||
// Act
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<HubOptions<ComponentHub>>>();
|
||||
|
||||
// Assert
|
||||
var protocol = Assert.Single(options.Value.SupportedProtocols);
|
||||
Assert.Equal(BlazorPackHubProtocol.ProtocolName, protocol);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddServerSideSignalR_RespectsGlobalHubOptions()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddServerSideBlazor();
|
||||
|
||||
services.Configure<HubOptions>(options =>
|
||||
{
|
||||
options.SupportedProtocols.Add("test");
|
||||
options.HandshakeTimeout = TimeSpan.FromMinutes(10);
|
||||
});
|
||||
|
||||
// Act
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<HubOptions<ComponentHub>>>();
|
||||
|
||||
// Assert
|
||||
var protocol = Assert.Single(options.Value.SupportedProtocols);
|
||||
Assert.Equal(BlazorPackHubProtocol.ProtocolName, protocol);
|
||||
Assert.Equal(TimeSpan.FromMinutes(10), options.Value.HandshakeTimeout);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddServerSideSignalR_ConfiguresGlobalOptionsBeforePerHubOptions()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddServerSideBlazor().AddHubOptions(options =>
|
||||
{
|
||||
Assert.Equal(TimeSpan.FromMinutes(10), options.HandshakeTimeout);
|
||||
options.HandshakeTimeout = TimeSpan.FromMinutes(5);
|
||||
});
|
||||
|
||||
services.Configure<HubOptions>(options =>
|
||||
{
|
||||
options.SupportedProtocols.Add("test");
|
||||
options.HandshakeTimeout = TimeSpan.FromMinutes(10);
|
||||
});
|
||||
|
||||
// Act
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<HubOptions<ComponentHub>>>();
|
||||
var globalOptions = services.BuildServiceProvider().GetRequiredService<IOptions<HubOptions>>();
|
||||
|
||||
// Assert
|
||||
var protocol = Assert.Single(options.Value.SupportedProtocols);
|
||||
Assert.Equal(BlazorPackHubProtocol.ProtocolName, protocol);
|
||||
Assert.Equal(TimeSpan.FromMinutes(5), options.Value.HandshakeTimeout);
|
||||
|
||||
// Configuring Blazor options is kept separate from the global options.
|
||||
Assert.Equal(TimeSpan.FromMinutes(10), globalOptions.Value.HandshakeTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,10 +15,10 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\Components\test\Rendering\HtmlRendererTestBase.cs" />
|
||||
<Compile Include="$(SignalRTestBase)HubMessageHelpers.cs" LinkBase="BlazorPack"/>
|
||||
<Compile Include="$(SignalRTestBase)MessagePackHubProtocolTestBase.cs" LinkBase="BlazorPack"/>
|
||||
<Compile Include="$(SignalRTestBase)TestBinder.cs" LinkBase="BlazorPack"/>
|
||||
<Compile Include="$(SignalRTestBase)TestHubMessageEqualityComparer.cs" LinkBase="BlazorPack"/>
|
||||
<Compile Include="$(SignalRTestBase)HubMessageHelpers.cs" LinkBase="BlazorPack" />
|
||||
<Compile Include="$(SignalRTestBase)MessagePackHubProtocolTestBase.cs" LinkBase="BlazorPack" />
|
||||
<Compile Include="$(SignalRTestBase)TestBinder.cs" LinkBase="BlazorPack" />
|
||||
<Compile Include="$(SignalRTestBase)TestHubMessageEqualityComparer.cs" LinkBase="BlazorPack" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -55,18 +55,11 @@ namespace TestServer
|
|||
{
|
||||
subdirApp.UseClientSideBlazorFiles<BasicTestApp.Startup>();
|
||||
|
||||
// The following two lines are equivalent to:
|
||||
// endpoints.MapComponentsHub<Index>();
|
||||
//
|
||||
// However it's expressed using routing as a way of checking that
|
||||
// we're not relying on any extra magic inside MapComponentsHub, since it's
|
||||
// important that people can set up these bits of middleware manually (e.g., to
|
||||
// swap in UseAzureSignalR instead of UseSignalR).
|
||||
subdirApp.UseRouting();
|
||||
|
||||
subdirApp.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapHub<ComponentHub>(ComponentHub.DefaultPath).AddComponent(typeof(Index), selector: "root");
|
||||
endpoints.MapBlazorHub(typeof(Index), selector: "root");
|
||||
endpoints.MapFallbackToClientSideBlazor<BasicTestApp.Startup>("index.html");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue