Pass options to HubConnectionContext (#11382)

This commit is contained in:
Brennan 2019-06-20 13:18:12 -07:00 committed by GitHub
parent c987ce5b3c
commit e8181ae479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 141 additions and 52 deletions

View File

@ -20,7 +20,12 @@ namespace Microsoft.AspNetCore.SignalR.Tests
{
public static HubConnectionContext Create(ConnectionContext connection, IHubProtocol protocol = null, string userIdentifier = null)
{
return new HubConnectionContext(connection, TimeSpan.FromSeconds(15), NullLoggerFactory.Instance)
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(15),
};
return new HubConnectionContext(connection, contextOptions, NullLoggerFactory.Instance)
{
Protocol = protocol ?? new JsonHubProtocol(),
UserIdentifier = userIdentifier,
@ -29,15 +34,20 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public static MockHubConnectionContext CreateMock(ConnectionContext connection)
{
return new MockHubConnectionContext(connection, TimeSpan.FromSeconds(15), NullLoggerFactory.Instance, TimeSpan.FromSeconds(15), streamBufferCapacity: 10);
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(15),
ClientTimeoutInterval = TimeSpan.FromSeconds(15),
StreamBufferCapacity = 10,
};
return new MockHubConnectionContext(connection, contextOptions, NullLoggerFactory.Instance);
}
public class MockHubConnectionContext : HubConnectionContext
{
public MockHubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory, TimeSpan clientTimeoutInterval, int streamBufferCapacity)
: base(connectionContext, keepAliveInterval, loggerFactory, clientTimeoutInterval, streamBufferCapacity)
public MockHubConnectionContext(ConnectionContext connectionContext, HubConnectionContextOptions contextOptions, ILoggerFactory loggerFactory)
: base(connectionContext, contextOptions, loggerFactory)
{
}
public override ValueTask WriteAsync(HubMessage message, CancellationToken cancellationToken = default)

View File

@ -46,7 +46,11 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
{
var pair = DuplexPipe.CreateConnectionPair(options, options);
var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Application, pair.Transport);
var hubConnection = new HubConnectionContext(connection, Timeout.InfiniteTimeSpan, NullLoggerFactory.Instance);
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = Timeout.InfiniteTimeSpan,
};
var hubConnection = new HubConnectionContext(connection, contextOptions, NullLoggerFactory.Instance);
hubConnection.Protocol = protocol;
_hubLifetimeManager.OnConnectedAsync(hubConnection).GetAwaiter().GetResult();
_hubLifetimeManager.AddToGroupAsync(connection.ConnectionId, TestGroupName).GetAwaiter().GetResult();

View File

@ -4,9 +4,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipelines;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
@ -46,7 +44,11 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Application, pair.Transport);
_connectionContext = new NoErrorHubConnectionContext(connection, TimeSpan.Zero, NullLoggerFactory.Instance);
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = TimeSpan.Zero,
};
_connectionContext = new NoErrorHubConnectionContext(connection, contextOptions, NullLoggerFactory.Instance);
_connectionContext.Protocol = new FakeHubProtocol();
}
@ -83,7 +85,8 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
{
public TaskCompletionSource<object> ReceivedCompleted = new TaskCompletionSource<object>();
public NoErrorHubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory) : base(connectionContext, keepAliveInterval, loggerFactory)
public NoErrorHubConnectionContext(ConnectionContext connectionContext, HubConnectionContextOptions contextOptions, ILoggerFactory loggerFactory)
: base(connectionContext, contextOptions, loggerFactory)
{
}

View File

@ -51,7 +51,11 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
ConnectionId = connectionId,
Transport = new TestDuplexPipe(ForceAsync)
};
var hubConnectionContext = new HubConnectionContext(connectionContext, TimeSpan.Zero, NullLoggerFactory.Instance);
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = TimeSpan.Zero,
};
var hubConnectionContext = new HubConnectionContext(connectionContext, contextOptions, NullLoggerFactory.Instance);
hubConnectionContext.UserIdentifier = userIdentifier;
hubConnectionContext.Protocol = jsonHubProtocol;

View File

@ -9,7 +9,6 @@ using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.AspNetCore.SignalR.Microbenchmarks.Shared;
@ -44,7 +43,11 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
_pipe = new TestDuplexPipe();
var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), _pipe, _pipe);
_hubConnectionContext = new HubConnectionContext(connection, Timeout.InfiniteTimeSpan, NullLoggerFactory.Instance);
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = Timeout.InfiniteTimeSpan,
};
_hubConnectionContext = new HubConnectionContext(connection, contextOptions, NullLoggerFactory.Instance);
_successHubProtocolResolver = new TestHubProtocolResolver(new NewtonsoftJsonHubProtocol());
_failureHubProtocolResolver = new TestHubProtocolResolver(null);

View File

@ -127,9 +127,7 @@ namespace Microsoft.AspNetCore.SignalR
}
public partial class HubConnectionContext
{
public HubConnectionContext(Microsoft.AspNetCore.Connections.ConnectionContext connectionContext, System.TimeSpan keepAliveInterval, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
public HubConnectionContext(Microsoft.AspNetCore.Connections.ConnectionContext connectionContext, System.TimeSpan keepAliveInterval, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.TimeSpan clientTimeoutInterval) { }
public HubConnectionContext(Microsoft.AspNetCore.Connections.ConnectionContext connectionContext, System.TimeSpan keepAliveInterval, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.TimeSpan clientTimeoutInterval, int streamBufferCapacity) { }
public HubConnectionContext(Microsoft.AspNetCore.Connections.ConnectionContext connectionContext, Microsoft.AspNetCore.SignalR.HubConnectionContextOptions contextOptions, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
public virtual System.Threading.CancellationToken ConnectionAborted { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public virtual string ConnectionId { get { throw null; } }
public virtual Microsoft.AspNetCore.Http.Features.IFeatureCollection Features { get { throw null; } }
@ -141,6 +139,13 @@ namespace Microsoft.AspNetCore.SignalR
public virtual System.Threading.Tasks.ValueTask WriteAsync(Microsoft.AspNetCore.SignalR.Protocol.HubMessage message, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual System.Threading.Tasks.ValueTask WriteAsync(Microsoft.AspNetCore.SignalR.SerializedHubMessage message, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
public partial class HubConnectionContextOptions
{
public HubConnectionContextOptions() { }
public System.TimeSpan ClientTimeoutInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.TimeSpan KeepAliveInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public int StreamBufferCapacity { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
public partial class HubConnectionHandler<THub> : Microsoft.AspNetCore.Connections.ConnectionHandler where THub : Microsoft.AspNetCore.SignalR.Hub
{
public HubConnectionHandler(Microsoft.AspNetCore.SignalR.HubLifetimeManager<THub> lifetimeManager, Microsoft.AspNetCore.SignalR.IHubProtocolResolver protocolResolver, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.SignalR.HubOptions> globalHubOptions, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.SignalR.HubOptions<THub>> hubOptions, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.SignalR.IUserIdProvider userIdProvider, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory) { }

View File

@ -48,37 +48,17 @@ namespace Microsoft.AspNetCore.SignalR
/// Initializes a new instance of the <see cref="HubConnectionContext"/> class.
/// </summary>
/// <param name="connectionContext">The underlying <see cref="ConnectionContext"/>.</param>
/// <param name="keepAliveInterval">The keep alive interval. If no messages are sent by the server in this interval, a Ping message will be sent.</param>
/// <param name="loggerFactory">The logger factory.</param>
public HubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory)
: this(connectionContext, keepAliveInterval, loggerFactory, HubOptionsSetup.DefaultClientTimeoutInterval, HubOptionsSetup.DefaultStreamBufferCapacity) { }
/// <summary>
/// Initializes a new instance of the <see cref="HubConnectionContext"/> class.
/// </summary>
/// <param name="connectionContext">The underlying <see cref="ConnectionContext"/>.</param>
/// <param name="keepAliveInterval">The keep alive interval. If no messages are sent by the server in this interval, a Ping message will be sent.</param>
/// <param name="loggerFactory">The logger factory.</param>
/// <param name="clientTimeoutInterval">Clients we haven't heard from in this interval are assumed to have disconnected.</param>
public HubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory, TimeSpan clientTimeoutInterval)
: this(connectionContext, keepAliveInterval, loggerFactory, clientTimeoutInterval, HubOptionsSetup.DefaultStreamBufferCapacity) { }
/// <summary>
/// Initializes a new instance of the <see cref="HubConnectionContext"/> class.
/// </summary>
/// <param name="connectionContext">The underlying <see cref="ConnectionContext"/>.</param>
/// <param name="keepAliveInterval">The keep alive interval. If no messages are sent by the server in this interval, a Ping message will be sent.</param>
/// <param name="loggerFactory">The logger factory.</param>
/// <param name="clientTimeoutInterval">Clients we haven't heard from in this interval are assumed to have disconnected.</param>
/// <param name="streamBufferCapacity">The buffer size for client upload streams</param>
public HubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory, TimeSpan clientTimeoutInterval, int streamBufferCapacity)
/// <param name="contextOptions">The options to configure the HubConnectionContext.</param>
public HubConnectionContext(ConnectionContext connectionContext, HubConnectionContextOptions contextOptions, ILoggerFactory loggerFactory)
{
_keepAliveInterval = contextOptions.KeepAliveInterval.Ticks;
_clientTimeoutInterval = contextOptions.ClientTimeoutInterval.Ticks;
_streamBufferCapacity = contextOptions.StreamBufferCapacity;
_connectionContext = connectionContext;
_logger = loggerFactory.CreateLogger<HubConnectionContext>();
ConnectionAborted = _connectionAbortedTokenSource.Token;
_keepAliveInterval = keepAliveInterval.Ticks;
_clientTimeoutInterval = clientTimeoutInterval.Ticks;
_streamBufferCapacity = streamBufferCapacity;
}
internal StreamTracker StreamTracker

View File

@ -0,0 +1,28 @@
// 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;
namespace Microsoft.AspNetCore.SignalR
{
/// <summary>
/// Options used to configure <see cref="HubConnectionContext"/>.
/// </summary>
public class HubConnectionContextOptions
{
/// <summary>
/// Gets or sets the interval used to send keep alive pings to connected clients.
/// </summary>
public TimeSpan KeepAliveInterval { get; set; }
/// <summary>
/// Gets or sets the time window clients have to send a message before the server closes the connection.
/// </summary>
public TimeSpan ClientTimeoutInterval { get; set; }
/// <summary>
/// Gets or sets the max buffer size for client upload streams.
/// </summary>
public int StreamBufferCapacity { get; set; }
}
}

View File

@ -11,7 +11,6 @@ using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.SignalR
@ -75,21 +74,26 @@ namespace Microsoft.AspNetCore.SignalR
public override async Task OnConnectedAsync(ConnectionContext connection)
{
// We check to see if HubOptions<THub> are set because those take precedence over global hub options.
// Then set the keepAlive and handshakeTimeout values to the defaults in HubOptionsSetup incase they were explicitly set to null.
var keepAlive = _hubOptions.KeepAliveInterval ?? _globalHubOptions.KeepAliveInterval ?? HubOptionsSetup.DefaultKeepAliveInterval;
var clientTimeout = _hubOptions.ClientTimeoutInterval ?? _globalHubOptions.ClientTimeoutInterval ?? HubOptionsSetup.DefaultClientTimeoutInterval;
var handshakeTimeout = _hubOptions.HandshakeTimeout ?? _globalHubOptions.HandshakeTimeout ?? HubOptionsSetup.DefaultHandshakeTimeout;
var streamBufferCapacity = _hubOptions.StreamBufferCapacity ?? _globalHubOptions.StreamBufferCapacity ?? HubOptionsSetup.DefaultStreamBufferCapacity;
var supportedProtocols = _hubOptions.SupportedProtocols ?? _globalHubOptions.SupportedProtocols;
// Then set the keepAlive and handshakeTimeout values to the defaults in HubOptionsSetup when they were explicitly set to null.
if (supportedProtocols != null && supportedProtocols.Count == 0)
var supportedProtocols = _hubOptions.SupportedProtocols ?? _globalHubOptions.SupportedProtocols;
if (supportedProtocols == null || supportedProtocols.Count == 0)
{
throw new InvalidOperationException("There are no supported protocols");
}
var handshakeTimeout = _hubOptions.HandshakeTimeout ?? _globalHubOptions.HandshakeTimeout ?? HubOptionsSetup.DefaultHandshakeTimeout;
var contextOptions = new HubConnectionContextOptions()
{
KeepAliveInterval = _hubOptions.KeepAliveInterval ?? _globalHubOptions.KeepAliveInterval ?? HubOptionsSetup.DefaultKeepAliveInterval,
ClientTimeoutInterval = _hubOptions.ClientTimeoutInterval ?? _globalHubOptions.ClientTimeoutInterval ?? HubOptionsSetup.DefaultClientTimeoutInterval,
StreamBufferCapacity = _hubOptions.StreamBufferCapacity ?? _globalHubOptions.StreamBufferCapacity ?? HubOptionsSetup.DefaultStreamBufferCapacity,
};
Log.ConnectedStarting(_logger);
var connectionContext = new HubConnectionContext(connection, keepAlive, _loggerFactory, clientTimeout, streamBufferCapacity);
var connectionContext = new HubConnectionContext(connection, contextOptions, _loggerFactory);
var resolvedSupportedProtocols = (supportedProtocols as IReadOnlyList<string>) ?? supportedProtocols.ToList();
if (!await connectionContext.HandshakeAsync(handshakeTimeout, resolvedSupportedProtocols, _protocolResolver, _userIdProvider, _enableDetailedErrors))

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.SignalR
// for all available protocols.
/// <summary>
/// Gets or sets the interval used by the server to timeout incoming handshake requests by clients. The default timeout is 15 seconds
/// Gets or sets the interval used by the server to timeout incoming handshake requests by clients. The default timeout is 15 seconds.
/// </summary>
public TimeSpan? HandshakeTimeout { get; set; } = null;

View File

@ -2309,6 +2309,54 @@ namespace Microsoft.AspNetCore.SignalR.Tests
}
}
[Fact]
public async Task HubOptionsCanNotHaveNullSupportedProtocols()
{
using (StartVerifiableLog())
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(services =>
{
services.AddSignalR(o =>
{
o.SupportedProtocols = null;
});
}, LoggerFactory);
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<MethodHub>>();
var msgPackOptions = serviceProvider.GetRequiredService<IOptions<MessagePackHubProtocolOptions>>();
using (var client = new TestClient(protocol: new MessagePackHubProtocol(msgPackOptions)))
{
client.SupportedFormats = TransferFormat.Binary;
await Assert.ThrowsAsync<InvalidOperationException>(async () => await await client.ConnectAsync(connectionHandler, expectedHandshakeResponseMessage: false)).OrTimeout();
}
}
}
[Fact]
public async Task HubOptionsCanNotHaveEmptySupportedProtocols()
{
using (StartVerifiableLog())
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(services =>
{
services.AddSignalR(o =>
{
o.SupportedProtocols = new List<string>();
});
}, LoggerFactory);
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<MethodHub>>();
var msgPackOptions = serviceProvider.GetRequiredService<IOptions<MessagePackHubProtocolOptions>>();
using (var client = new TestClient(protocol: new MessagePackHubProtocol(msgPackOptions)))
{
client.SupportedFormats = TransferFormat.Binary;
await Assert.ThrowsAsync<InvalidOperationException>(async () => await await client.ConnectAsync(connectionHandler, expectedHandshakeResponseMessage: false)).OrTimeout();
}
}
}
[Fact]
public async Task ConnectionUserIdIsAssignedByUserIdProvider()
{