This commit is contained in:
James Newton-King 2018-04-17 20:39:19 +12:00
commit 8985fee4b5
No known key found for this signature in database
GPG Key ID: 0A66B2F456BF5526
108 changed files with 1307 additions and 440 deletions

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
var hubConnection = new HubConnectionContext(connection, Timeout.InfiniteTimeSpan, NullLoggerFactory.Instance);
hubConnection.Protocol = protocol;
_hubLifetimeManager.OnConnectedAsync(hubConnection).GetAwaiter().GetResult();
_hubLifetimeManager.AddGroupAsync(connection.ConnectionId, TestGroupName).GetAwaiter().GetResult();
_hubLifetimeManager.AddToGroupAsync(connection.ConnectionId, TestGroupName).GetAwaiter().GetResult();
_ = ConsumeAsync(connection.Application);
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
hubConnectionContext.Protocol = jsonHubProtocol;
_hubLifetimeManager.OnConnectedAsync(hubConnectionContext).GetAwaiter().GetResult();
_hubLifetimeManager.AddGroupAsync(connectionId, groupName);
_hubLifetimeManager.AddToGroupAsync(connectionId, groupName);
}
}
@ -122,4 +122,4 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
return _hubLifetimeManager.SendUsersAsync(_userIdentifiers, "MethodName", Array.Empty<object>());
}
}
}
}

View File

@ -76,6 +76,6 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
public class TestConnectionInherentKeepAliveFeature : IConnectionInherentKeepAliveFeature
{
public TimeSpan KeepAliveInterval { get; } = TimeSpan.Zero;
public bool HasInherentKeepAlive { get; } = true;
}
}

View File

@ -1,9 +1,11 @@
// 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 System.Buffers;
using System.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
{

View File

@ -5,6 +5,11 @@
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\Common\BinaryMessageFormatter.cs" Link="BinaryMessageFormatter.cs" />
<Compile Include="..\..\src\Common\BinaryMessageParser.cs" Link="BinaryMessageParser.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Http.Connections.Client\Microsoft.AspNetCore.Http.Connections.Client.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Http.Connections\Microsoft.AspNetCore.Http.Connections.csproj" />

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Connections.Internal;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Internal;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
private RedisHubLifetimeManager<TestHub> _manager2;
private TestClient[] _clients;
private object[] _args;
private readonly List<string> _excludedIds = new List<string>();
private readonly List<string> _excludedConnectionIds = new List<string>();
private readonly List<string> _sendIds = new List<string>();
private readonly List<string> _groups = new List<string>();
private readonly List<string> _users = new List<string>();
@ -42,18 +42,18 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
var protocols = GenerateProtocols(ProtocolCount).ToArray();
var options = Options.Create(new RedisOptions()
{
Factory = _ => Task.FromResult<IConnectionMultiplexer>(new TestConnectionMultiplexer(server))
ConnectionFactory = _ => Task.FromResult<IConnectionMultiplexer>(new TestConnectionMultiplexer(server))
});
var resolver = new DefaultHubProtocolResolver(protocols, NullLogger<DefaultHubProtocolResolver>.Instance);
_manager1 = new RedisHubLifetimeManager<TestHub>(logger, options, resolver);
_manager2 = new RedisHubLifetimeManager<TestHub>(logger, options, resolver);
async Task ConnectClient(TestClient client, IHubProtocol protocol, string userId, string group)
async Task ConnectClient(TestClient client, IHubProtocol protocol, string userId, string groupName)
{
await _manager2.OnConnectedAsync(HubConnectionContextUtils.Create(client.Connection, protocol, userId));
await _manager2.AddGroupAsync(client.Connection.ConnectionId, "Everyone");
await _manager2.AddGroupAsync(client.Connection.ConnectionId, group);
await _manager2.AddToGroupAsync(client.Connection.ConnectionId, "Everyone");
await _manager2.AddToGroupAsync(client.Connection.ConnectionId, groupName);
}
// Connect clients
@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
{
group = "Evens";
user = "EvenUser";
_excludedIds.Add(_clients[i].Connection.ConnectionId);
_excludedConnectionIds.Add(_clients[i].Connection.ConnectionId);
}
else
{
@ -144,13 +144,13 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
[Benchmark]
public async Task SendAllExcept()
{
await _manager1.SendAllExceptAsync("Test", _args, _excludedIds);
await _manager1.SendAllExceptAsync("Test", _args, _excludedConnectionIds);
}
[Benchmark]
public async Task SendGroupExcept()
{
await _manager1.SendGroupExceptAsync("Everyone", "Test", _args, _excludedIds);
await _manager1.SendGroupExceptAsync("Everyone", "Test", _args, _excludedConnectionIds);
}
[Benchmark]

View File

@ -1,3 +1,6 @@
// 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 System.Buffers;
using System.Collections.Generic;
@ -14,8 +17,8 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
private RedisGroupCommand _groupCommand;
private object[] _args;
private string _methodName;
private IReadOnlyList<string> _excludedIdsSmall;
private IReadOnlyList<string> _excludedIdsLarge;
private IReadOnlyList<string> _excludedConnectionIdsSmall;
private IReadOnlyList<string> _excludedConnectionIdsLarge;
private byte[] _writtenAck;
private byte[] _writtenGroupCommand;
private byte[] _writtenInvocationNoExclusions;
@ -36,14 +39,14 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
_args = Array.Empty<object>();
_methodName = "Method";
_excludedIdsSmall = GenerateIds(2);
_excludedIdsLarge = GenerateIds(20);
_excludedConnectionIdsSmall = GenerateIds(2);
_excludedConnectionIdsLarge = GenerateIds(20);
_writtenAck = _protocol.WriteAck(42);
_writtenGroupCommand = _protocol.WriteGroupCommand(_groupCommand);
_writtenInvocationNoExclusions = _protocol.WriteInvocation(_methodName, _args, null);
_writtenInvocationSmallExclusions = _protocol.WriteInvocation(_methodName, _args, _excludedIdsSmall);
_writtenInvocationLargeExclusions = _protocol.WriteInvocation(_methodName, _args, _excludedIdsLarge);
_writtenInvocationSmallExclusions = _protocol.WriteInvocation(_methodName, _args, _excludedConnectionIdsSmall);
_writtenInvocationLargeExclusions = _protocol.WriteInvocation(_methodName, _args, _excludedConnectionIdsLarge);
}
[Benchmark]
@ -67,13 +70,13 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
[Benchmark]
public void WriteInvocationSmallExclusions()
{
_protocol.WriteInvocation(_methodName, _args, _excludedIdsSmall);
_protocol.WriteInvocation(_methodName, _args, _excludedConnectionIdsSmall);
}
[Benchmark]
public void WriteInvocationLargeExclusions()
{
_protocol.WriteInvocation(_methodName, _args, _excludedIdsLarge);
_protocol.WriteInvocation(_methodName, _args, _excludedConnectionIdsLarge);
}
[Benchmark]

View File

@ -1,13 +0,0 @@
// 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.Connections.Features;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks.Shared
{
public class TestConnectionInherentKeepAliveFeature : IConnectionInherentKeepAliveFeature
{
public TimeSpan KeepAliveInterval { get; } = TimeSpan.Zero;
}
}

View File

@ -1,76 +1,76 @@
<Project>
<Project>
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<PropertyGroup Label="Package Versions">
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
<GoogleProtobufPackageVersion>3.1.0</GoogleProtobufPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview3-17002</InternalAspNetCoreSdkPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview3-17018</InternalAspNetCoreSdkPackageVersion>
<MessagePackPackageVersion>1.7.3.4</MessagePackPackageVersion>
<MicrosoftAspNetCoreAllPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreAllPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>
<MicrosoftAspNetCoreAuthorizationPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreAuthorizationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsEntityFrameworkCorePackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreDiagnosticsEntityFrameworkCorePackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreIdentityEntityFrameworkCorePackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreIdentityEntityFrameworkCorePackageVersion>
<MicrosoftAspNetCoreMvcPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreMvcPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.5.0-preview2-32196</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebSocketsPackageVersion>2.1.0-preview3-32196</MicrosoftAspNetCoreWebSocketsPackageVersion>
<MicrosoftCSharpPackageVersion>4.5.0-preview2-26406-04</MicrosoftCSharpPackageVersion>
<MicrosoftEntityFrameworkCoreDesignPackageVersion>2.1.0-preview3-32196</MicrosoftEntityFrameworkCoreDesignPackageVersion>
<MicrosoftEntityFrameworkCoreSqlServerPackageVersion>2.1.0-preview3-32196</MicrosoftEntityFrameworkCoreSqlServerPackageVersion>
<MicrosoftEntityFrameworkCoreToolsPackageVersion>2.1.0-preview3-32196</MicrosoftEntityFrameworkCoreToolsPackageVersion>
<MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConfigurationPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsLoggingConfigurationPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersSourcesPackageVersion>2.1.0-preview3-32196</MicrosoftExtensionsWebEncodersSourcesPackageVersion>
<MicrosoftAspNetCoreAllPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreAllPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>
<MicrosoftAspNetCoreAuthorizationPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreAuthorizationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion>2.1.0-a-preview3-inherent-keep-alive-bool-17670</MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsEntityFrameworkCorePackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreDiagnosticsEntityFrameworkCorePackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreIdentityEntityFrameworkCorePackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreIdentityEntityFrameworkCorePackageVersion>
<MicrosoftAspNetCoreMvcPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreMvcPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.5.0-preview2-32233</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.0-a-preview3-inherent-keep-alive-bool-17670</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebSocketsPackageVersion>2.1.0-preview3-32233</MicrosoftAspNetCoreWebSocketsPackageVersion>
<MicrosoftCSharpPackageVersion>4.5.0-preview3-26413-02</MicrosoftCSharpPackageVersion>
<MicrosoftEntityFrameworkCoreDesignPackageVersion>2.1.0-preview3-32233</MicrosoftEntityFrameworkCoreDesignPackageVersion>
<MicrosoftEntityFrameworkCoreSqlServerPackageVersion>2.1.0-preview3-32233</MicrosoftEntityFrameworkCoreSqlServerPackageVersion>
<MicrosoftEntityFrameworkCoreToolsPackageVersion>2.1.0-preview3-32233</MicrosoftEntityFrameworkCoreToolsPackageVersion>
<MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConfigurationPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsLoggingConfigurationPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersSourcesPackageVersion>2.1.0-preview3-32233</MicrosoftExtensionsWebEncodersSourcesPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26406-04</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview3-26413-05</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
<StackExchangeRedisStrongNamePackageVersion>1.2.4</StackExchangeRedisStrongNamePackageVersion>
<SystemBuffersPackageVersion>4.5.0-preview2-26406-04</SystemBuffersPackageVersion>
<SystemIOPipelinesPackageVersion>4.5.0-preview2-26406-04</SystemIOPipelinesPackageVersion>
<SystemMemoryPackageVersion>4.5.0-preview2-26406-04</SystemMemoryPackageVersion>
<SystemNumericsVectorsPackageVersion>4.5.0-preview2-26406-04</SystemNumericsVectorsPackageVersion>
<SystemBuffersPackageVersion>4.5.0-preview3-26413-02</SystemBuffersPackageVersion>
<SystemIOPipelinesPackageVersion>4.5.0-preview3-26413-02</SystemIOPipelinesPackageVersion>
<SystemMemoryPackageVersion>4.5.0-preview3-26413-02</SystemMemoryPackageVersion>
<SystemNumericsVectorsPackageVersion>4.5.0-preview3-26413-02</SystemNumericsVectorsPackageVersion>
<SystemReactiveLinqPackageVersion>3.1.1</SystemReactiveLinqPackageVersion>
<SystemReflectionEmitPackageVersion>4.3.0</SystemReflectionEmitPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview2-26406-04</SystemRuntimeCompilerServicesUnsafePackageVersion>
<SystemThreadingChannelsPackageVersion>4.5.0-preview2-26406-04</SystemThreadingChannelsPackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview2-26406-04</SystemThreadingTasksExtensionsPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview3-26413-02</SystemRuntimeCompilerServicesUnsafePackageVersion>
<SystemThreadingChannelsPackageVersion>4.5.0-preview3-26413-02</SystemThreadingChannelsPackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview3-26413-02</SystemThreadingTasksExtensionsPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup>

View File

@ -1,6 +1,6 @@
{
"name": "@aspnet/signalr-protocol-msgpack",
"version": "1.0.0-preview3-t000",
"version": "1.1.0-preview1-t000",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@aspnet/signalr-protocol-msgpack",
"version": "1.0.0-preview3-t000",
"version": "1.1.0-preview1-t000",
"description": "MsgPack Protocol support for ASP.NET Core SignalR",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",

View File

@ -1,6 +1,6 @@
{
"name": "@aspnet/signalr",
"version": "1.0.0-preview3-t000",
"version": "1.1.0-preview1-t000",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@aspnet/signalr",
"version": "1.0.0-preview3-t000",
"version": "1.1.0-preview1-t000",
"description": "ASP.NET Core SignalR Client",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",

View File

@ -288,13 +288,73 @@ describe("HttpConnection", () => {
}
});
it("sets inherentKeepAlive feature when using LongPolling", async (done) => {
it("authorization header removed when token factory returns null and using LongPolling", async (done) => {
const availableTransport = { transport: "LongPolling", transferFormats: ["Text"] };
var httpClientGetCount = 0;
var accessTokenFactoryCount = 0;
const options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient()
.on("POST", (r) => ({ connectionId: "42", availableTransports: [availableTransport] })),
.on("POST", (r) => ({ connectionId: "42", availableTransports: [availableTransport] }))
.on("GET", (r) => {
httpClientGetCount++;
const authorizationValue = r.headers["Authorization"];
if (httpClientGetCount == 1) {
if (authorizationValue) {
fail("First long poll request should have a authorization header.");
}
// First long polling request must succeed so start completes
return "";
} else {
// Check second long polling request has its header removed
if (authorizationValue) {
fail("Second long poll request should have no authorization header.");
}
throw new Error("fail");
}
}),
accessTokenFactory: () => {
accessTokenFactoryCount++;
if (accessTokenFactoryCount == 1) {
return "A token value";
} else {
// Return a null value after the first call to test the header being removed
return null;
}
},
} as IHttpConnectionOptions;
const connection = new HttpConnection("http://tempuri.org", options);
try {
await connection.start(TransferFormat.Text);
expect(httpClientGetCount).toBeGreaterThanOrEqual(2);
expect(accessTokenFactoryCount).toBeGreaterThanOrEqual(2);
done();
} catch (e) {
fail(e);
done();
}
});
it("sets inherentKeepAlive feature when using LongPolling", async (done) => {
const availableTransport = { transport: "LongPolling", transferFormats: ["Text"] };
var httpClientGetCount = 0;
const options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient()
.on("POST", (r) => ({ connectionId: "42", availableTransports: [availableTransport] }))
.on("GET", (r) => {
httpClientGetCount++;
if (httpClientGetCount == 1) {
// First long polling request must succeed so start completes
return "";
} else {
throw new Error("fail");
}
}),
} as IHttpConnectionOptions;
const connection = new HttpConnection("http://tempuri.org", options);

View File

@ -31,7 +31,7 @@ export class LongPollingTransport implements ITransport {
this.logMessageContent = logMessageContent;
}
public connect(url: string, transferFormat: TransferFormat): Promise<void> {
public async connect(url: string, transferFormat: TransferFormat): Promise<void> {
Arg.isRequired(url, "url");
Arg.isRequired(transferFormat, "transferFormat");
Arg.isIn(transferFormat, TransferFormat, "transferFormat");
@ -45,13 +45,6 @@ export class LongPollingTransport implements ITransport {
throw new Error("Binary protocols over XmlHttpRequest not implementing advanced features are not supported.");
}
this.poll(this.url, transferFormat);
return Promise.resolve();
}
private async poll(url: string, transferFormat: TransferFormat): Promise<void> {
this.running = true;
const pollOptions: HttpRequest = {
abortSignal: this.pollAbort.signal,
headers: {},
@ -62,15 +55,49 @@ export class LongPollingTransport implements ITransport {
pollOptions.responseType = "arraybuffer";
}
const token = await this.accessTokenFactory();
this.updateHeaderToken(pollOptions, token);
let closeError: Error;
// Make initial long polling request
// Server uses first long polling request to finish initializing connection and it returns without data
const pollUrl = `${url}&_=${Date.now()}`;
this.logger.log(LogLevel.Trace, `(LongPolling transport) polling: ${pollUrl}`);
const response = await this.httpClient.get(pollUrl, pollOptions);
if (response.statusCode !== 200) {
this.logger.log(LogLevel.Error, `(LongPolling transport) Unexpected response code: ${response.statusCode}`);
// Mark running as false so that the poll immediately ends and runs the close logic
closeError = new HttpError(response.statusText, response.statusCode);
this.running = false;
} else {
this.running = true;
}
this.poll(this.url, pollOptions, closeError);
return Promise.resolve();
}
private updateHeaderToken(request: HttpRequest, token: string) {
if (token) {
// tslint:disable-next-line:no-string-literal
request.headers["Authorization"] = `Bearer ${token}`;
return;
}
// tslint:disable-next-line:no-string-literal
if (request.headers["Authorization"]) {
// tslint:disable-next-line:no-string-literal
delete request.headers["Authorization"];
}
}
private async poll(url: string, pollOptions: HttpRequest, closeError: Error): Promise<void> {
try {
while (this.running) {
// We have to get the access token on each poll, in case it changes
const token = await this.accessTokenFactory();
if (token) {
// tslint:disable-next-line:no-string-literal
pollOptions.headers["Authorization"] = `Bearer ${token}`;
}
this.updateHeaderToken(pollOptions, token);
try {
const pollUrl = `${url}&_=${Date.now()}`;
@ -142,14 +169,11 @@ export class LongPollingTransport implements ITransport {
this.running = false;
this.logger.log(LogLevel.Trace, `(LongPolling transport) sending DELETE request to ${this.url}.`);
const deleteOptions: HttpRequest = {};
const deleteOptions: HttpRequest = {
headers: {},
};
const token = await this.accessTokenFactory();
if (token) {
// tslint:disable-next-line:no-string-literal
deleteOptions.headers = {
["Authorization"]: `Bearer ${token}`,
};
}
this.updateHeaderToken(deleteOptions, token);
const response = await this.httpClient.delete(this.url, deleteOptions);
this.logger.log(LogLevel.Trace, "(LongPolling transport) DELETE request accepted.");

View File

@ -1,2 +1,2 @@
version:2.1.0-preview3-17002
commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f
version:2.1.0-preview3-17018
commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be

View File

@ -143,9 +143,9 @@ namespace ChatSample
return _wrappedHubLifetimeManager.SendAllAsync(methodName, args);
}
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedIds)
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
return _wrappedHubLifetimeManager.SendAllExceptAsync(methodName, args, excludedIds);
return _wrappedHubLifetimeManager.SendAllExceptAsync(methodName, args, excludedConnectionIds);
}
public override Task SendConnectionAsync(string connectionId, string methodName, object[] args)
@ -173,19 +173,19 @@ namespace ChatSample
return _wrappedHubLifetimeManager.SendUserAsync(userId, methodName, args);
}
public override Task AddGroupAsync(string connectionId, string groupName)
public override Task AddToGroupAsync(string connectionId, string groupName)
{
return _wrappedHubLifetimeManager.AddGroupAsync(connectionId, groupName);
return _wrappedHubLifetimeManager.AddToGroupAsync(connectionId, groupName);
}
public override Task RemoveGroupAsync(string connectionId, string groupName)
public override Task RemoveFromGroupAsync(string connectionId, string groupName)
{
return _wrappedHubLifetimeManager.RemoveGroupAsync(connectionId, groupName);
return _wrappedHubLifetimeManager.RemoveFromGroupAsync(connectionId, groupName);
}
public override Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedIds)
public override Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
return _wrappedHubLifetimeManager.SendGroupExceptAsync(groupName, methodName, args, excludedIds);
return _wrappedHubLifetimeManager.SendGroupExceptAsync(groupName, methodName, args, excludedConnectionIds);
}
public override Task SendUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args)

View File

@ -65,7 +65,7 @@ namespace ChatSample
{
// TODO: handle connection failures
_redisConnection = await ConnectToRedis(_options, _logger);
_redisDatabase = _redisConnection.GetDatabase(_options.Options.DefaultDatabase.GetValueOrDefault());
_redisDatabase = _redisConnection.GetDatabase(_options.Configuration.DefaultDatabase.GetValueOrDefault());
// Register connection
_redisDatabase.SetAdd(ServerIndexRedisKey, ServerId);
@ -103,14 +103,14 @@ namespace ChatSample
private static async Task<IConnectionMultiplexer> ConnectToRedis(RedisOptions options, ILogger logger)
{
var loggerTextWriter = new LoggerTextWriter(logger);
if (options.Factory != null)
if (options.ConnectionFactory != null)
{
return await options.Factory(loggerTextWriter);
return await options.ConnectionFactory(loggerTextWriter);
}
if (options.Options.EndPoints.Any())
if (options.Configuration.EndPoints.Any())
{
return await ConnectionMultiplexer.ConnectAsync(options.Options, loggerTextWriter);
return await ConnectionMultiplexer.ConnectAsync(options.Configuration, loggerTextWriter);
}
var configurationOptions = new ConfigurationOptions();

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipelines;
@ -40,7 +40,8 @@ namespace ClientSample
public override string ConnectionId { get; set; } = Guid.NewGuid().ToString();
public override IDictionary<object, object> Items { get; set; } = new ConnectionItems();
public TimeSpan KeepAliveInterval => Timeout.InfiniteTimeSpan;
// We claim to have inherent keep-alive so the client doesn't kill the connection when it hasn't seen ping frames.
public bool HasInherentKeepAlive { get; } = true;
public Task DisposeAsync()
{

View File

@ -46,7 +46,7 @@ namespace SignalRSamples.Hubs
public async Task JoinGroup(string groupName)
{
await Groups.AddAsync(Context.ConnectionId, groupName);
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} joined {groupName}");
}
@ -55,7 +55,7 @@ namespace SignalRSamples.Hubs
{
await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} left {groupName}");
await Groups.RemoveAsync(Context.ConnectionId, groupName);
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
public Task Echo(string message)

View File

@ -41,7 +41,7 @@ namespace SignalRSamples.Hubs
public async Task JoinGroup(string groupName)
{
await Groups.AddAsync(Context.ConnectionId, groupName);
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).Send($"{Context.ConnectionId} joined {groupName}");
}
@ -50,7 +50,7 @@ namespace SignalRSamples.Hubs
{
await Clients.Group(groupName).Send($"{Context.ConnectionId} left {groupName}");
await Groups.RemoveAsync(Context.ConnectionId, groupName);
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
public Task Echo(string message)

View File

@ -41,7 +41,7 @@ namespace SignalRSamples.Hubs
public async Task JoinGroup(string groupName)
{
await Groups.AddAsync(Context.ConnectionId, groupName);
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).Send($"{Context.ConnectionId} joined {groupName}");
}
@ -50,7 +50,7 @@ namespace SignalRSamples.Hubs
{
await Clients.Group(groupName).Send($"{Context.ConnectionId} left {groupName}");
await Groups.RemoveAsync(Context.ConnectionId, groupName);
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
public Task Echo(string message)

View File

@ -4,9 +4,9 @@
using System;
using System.Buffers;
namespace Microsoft.AspNetCore.SignalR.Internal.Formatters
namespace Microsoft.AspNetCore.Internal
{
public static class BinaryMessageFormatter
internal static class BinaryMessageFormatter
{
public static void WriteLengthPrefix(long length, IBufferWriter<byte> output)
{

View File

@ -4,9 +4,9 @@
using System;
using System.Buffers;
namespace Microsoft.AspNetCore.SignalR.Internal.Formatters
namespace Microsoft.AspNetCore.Internal
{
public static class BinaryMessageParser
internal static class BinaryMessageParser
{
private const int MaxLengthPrefixSize = 5;

View File

@ -4,9 +4,9 @@
using System.Buffers;
using System.IO;
namespace Microsoft.AspNetCore.SignalR.Internal.Formatters
namespace Microsoft.AspNetCore.Internal
{
public static class TextMessageFormatter
internal static class TextMessageFormatter
{
// This record separator is supposed to be used only for JSON payloads where 0x1e character
// will not occur (is not a valid character) and therefore it is safe to not escape it

View File

@ -4,9 +4,9 @@
using System;
using System.Buffers;
namespace Microsoft.AspNetCore.SignalR.Internal.Formatters
namespace Microsoft.AspNetCore.Internal
{
public static class TextMessageParser
internal static class TextMessageParser
{
public static bool TryParseMessage(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> payload)
{

View File

@ -12,15 +12,13 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http.Connections.Client.Internal;
using Microsoft.AspNetCore.Http.Connections.Features;
using Microsoft.AspNetCore.Http.Connections.Internal;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Http.Connections.Client
{
public partial class HttpConnection : ConnectionContext
public partial class HttpConnection : ConnectionContext, IConnectionInherentKeepAliveFeature
{
private static readonly TimeSpan HttpClientTimeout = TimeSpan.FromSeconds(120);
#if !NETCOREAPP2_1
@ -32,6 +30,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
private readonly SemaphoreSlim _connectionLock = new SemaphoreSlim(1, 1);
private bool _started;
private bool _disposed;
private bool _hasInherentKeepAlive;
private readonly HttpClient _httpClient;
private readonly HttpConnectionOptions _httpConnectionOptions;
@ -60,6 +59,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
public override string ConnectionId { get; set; }
public override IDictionary<object, object> Items { get; set; } = new ConnectionItems();
bool IConnectionInherentKeepAliveFeature.HasInherentKeepAlive => _hasInherentKeepAlive;
public HttpConnection(Uri url)
: this(url, HttpTransports.All)
{ }
@ -103,6 +104,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
_transportFactory = new DefaultTransportFactory(httpConnectionOptions.Transports, _loggerFactory, _httpClient, httpConnectionOptions);
_logScope = new ConnectionLogScope();
_scopeDisposable = _logger.BeginScope(_logScope);
Features.Set<IConnectionInherentKeepAliveFeature>(this);
}
// Used by unit tests
@ -348,11 +351,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
throw;
}
if (transportType == HttpTransportType.LongPolling)
{
// Disable keep alives for long polling
Features.Set<IConnectionInherentKeepAliveFeature>(new ConnectionInherentKeepAliveFeature(_httpClient.Timeout));
}
// Disable keep alives for long polling
_hasInherentKeepAlive = transportType == HttpTransportType.LongPolling;
// We successfully started, set the transport properties (we don't want to set these until the transport is definitely running).
_transport = transport;
@ -466,4 +466,4 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
return negotiationResponse;
}
}
}
}

View File

@ -8,7 +8,6 @@ using System.Net.Http;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Connections.Internal;
namespace Microsoft.AspNetCore.Http.Connections.Client
{

View File

@ -5,7 +5,6 @@ using System;
using System.Net.Http;
using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.AspNetCore.Http.Connections.Client.Internal;
using Microsoft.AspNetCore.Http.Connections.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal

View File

@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<LongPollingTransport>();
}
public Task StartAsync(Uri url, TransferFormat transferFormat)
public async Task StartAsync(Uri url, TransferFormat transferFormat)
{
if (transferFormat != TransferFormat.Binary && transferFormat != TransferFormat.Text)
{
@ -49,6 +49,14 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
Log.StartTransport(_logger, transferFormat);
// Make initial long polling request
// Server uses first long polling request to finish initializing connection and it returns without data
var request = new HttpRequestMessage(HttpMethod.Get, url);
using (var response = await _httpClient.SendAsync(request))
{
response.EnsureSuccessStatusCode();
}
// Create the pipe pair (Application's writer is connected to Transport's reader, and vice versa)
var options = ClientPipeOptions.DefaultOptions;
var pair = DuplexPipe.CreateConnectionPair(options, options);
@ -57,8 +65,6 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
_application = pair.Application;
Running = ProcessAsync(url);
return Task.CompletedTask;
}
private async Task ProcessAsync(Uri url)
@ -105,6 +111,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
Log.TransportStopping(_logger);
if (_application == null)
{
// We never started
return;
}
_application.Input.CancelPendingRead();
try

View File

@ -11,7 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Http.Connections.Client
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
internal static class SendUtils
{

View File

@ -207,6 +207,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
Log.TransportStopping(_logger);
if (_application == null)
{
// We never started
return;
}
_transport.Output.Complete();
_transport.Input.Complete();

View File

@ -3,7 +3,7 @@
using System;
namespace Microsoft.AspNetCore.Http.Connections.Client
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
internal static class Utils
{

View File

@ -373,6 +373,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
Log.TransportStopping(_logger);
if (_application == null)
{
// We never started
return;
}
_transport.Output.Complete();
_transport.Input.Complete();

View File

@ -3,11 +3,11 @@
using System.Collections.Generic;
namespace Microsoft.AspNetCore.Http.Connections.Internal
namespace Microsoft.AspNetCore.Http.Connections
{
public class AvailableTransport
{
public string Transport { get; set; }
public List<string> TransferFormats { get; set; }
public IList<string> TransferFormats { get; set; }
}
}

View File

@ -1,18 +0,0 @@
// 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.Connections.Features;
namespace Microsoft.AspNetCore.Http.Connections.Features
{
public class ConnectionInherentKeepAliveFeature : IConnectionInherentKeepAliveFeature
{
public TimeSpan KeepAliveInterval { get; }
public ConnectionInherentKeepAliveFeature(TimeSpan keepAliveInterval)
{
KeepAliveInterval = keepAliveInterval;
}
}
}

View File

@ -1,7 +1,7 @@
// 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.AspNetCore.Http.Connections.Internal
namespace Microsoft.AspNetCore.Http.Connections
{
public static class HttpTransports
{

View File

@ -8,7 +8,7 @@ using System.IO;
using Microsoft.AspNetCore.Internal;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Http.Connections.Internal
namespace Microsoft.AspNetCore.Http.Connections
{
public static class NegotiateProtocol
{

View File

@ -3,11 +3,11 @@
using System.Collections.Generic;
namespace Microsoft.AspNetCore.Http.Connections.Internal
namespace Microsoft.AspNetCore.Http.Connections
{
public class NegotiationResponse
{
public string ConnectionId { get; set; }
public List<AvailableTransport> AvailableTransports { get; set; }
public IList<AvailableTransport> AvailableTransports { get; set; }
}
}

View File

@ -24,7 +24,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
IConnectionHeartbeatFeature,
ITransferFormatFeature,
IHttpContextFeature,
IHttpTransportFeature
IHttpTransportFeature,
IConnectionInherentKeepAliveFeature
{
private readonly object _itemsLock = new object();
private readonly object _heartbeatLock = new object();
@ -65,6 +66,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
Features.Set<ITransferFormatFeature>(this);
Features.Set<IHttpContextFeature>(this);
Features.Set<IHttpTransportFeature>(this);
Features.Set<IConnectionInherentKeepAliveFeature>(this);
}
public HttpConnectionContext(string id, IDuplexPipe transport, IDuplexPipe application, ILogger logger = null)
@ -97,6 +99,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
public ClaimsPrincipal User { get; set; }
public bool HasInherentKeepAlive { get; set; }
public override IDictionary<object, object> Items
{
get

View File

@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
using (connection.Cancellation)
{
// Cancel the previous request
connection.Cancellation.Cancel();
connection.Cancellation?.Cancel();
// Wait for the previous request to drain
await connection.TransportTask;
@ -228,29 +228,38 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
Log.EstablishedConnection(_logger);
connection.ApplicationTask = ExecuteApplication(connectionDelegate, connection);
context.Response.ContentType = "application/octet-stream";
// This request has no content
context.Response.ContentLength = 0;
// On the first poll, we flush the response immediately to mark the poll as "initialized" so future
// requests can be made safely
connection.TransportTask = context.Response.Body.FlushAsync();
}
else
{
Log.ResumingConnection(_logger);
// REVIEW: Performance of this isn't great as this does a bunch of per request allocations
connection.Cancellation = new CancellationTokenSource();
var timeoutSource = new CancellationTokenSource();
var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(connection.Cancellation.Token, context.RequestAborted, timeoutSource.Token);
// Dispose these tokens when the request is over
context.Response.RegisterForDispose(timeoutSource);
context.Response.RegisterForDispose(tokenSource);
var longPolling = new LongPollingTransport(timeoutSource.Token, connection.Application.Input, _loggerFactory);
// Start the transport
connection.TransportTask = longPolling.ProcessRequestAsync(context, tokenSource.Token);
// Start the timeout after we return from creating the transport task
timeoutSource.CancelAfter(options.LongPolling.PollTimeout);
}
// REVIEW: Performance of this isn't great as this does a bunch of per request allocations
connection.Cancellation = new CancellationTokenSource();
var timeoutSource = new CancellationTokenSource();
var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(connection.Cancellation.Token, context.RequestAborted, timeoutSource.Token);
// Dispose these tokens when the request is over
context.Response.RegisterForDispose(timeoutSource);
context.Response.RegisterForDispose(tokenSource);
var longPolling = new LongPollingTransport(timeoutSource.Token, connection.Application.Input, _loggerFactory);
// Start the transport
connection.TransportTask = longPolling.ProcessRequestAsync(context, tokenSource.Token);
// Start the timeout after we return from creating the transport task
timeoutSource.CancelAfter(options.LongPolling.PollTimeout);
}
finally
{
@ -302,7 +311,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
connection.Status = HttpConnectionStatus.Inactive;
// Dispose the cancellation token
connection.Cancellation.Dispose();
connection.Cancellation?.Dispose();
connection.Cancellation = null;
}
@ -366,10 +375,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
private async Task ExecuteApplication(ConnectionDelegate connectionDelegate, HttpConnectionContext connection)
{
// Verify some initialization invariants
// We want to be positive that the IConnectionInherentKeepAliveFeature is initialized before invoking the application, if the long polling transport is in use.
Debug.Assert(connection.TransportType != HttpTransportType.None, "Transport has not been initialized yet");
Debug.Assert(connection.TransportType != HttpTransportType.LongPolling ||
connection.Features.Get<IConnectionInherentKeepAliveFeature>() != null, "Long-polling transport is in use but IConnectionInherentKeepAliveFeature as not configured");
// Jump onto the thread pool thread so blocking user code doesn't block the setup of the
// connection and transport
@ -477,7 +483,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
context.Response.ContentType = "text/plain";
return;
}
await context.Request.Body.CopyToAsync(connection.ApplicationStream, bufferSize);
Log.ReceivedBytes(_logger, connection.ApplicationStream.Length);
@ -555,7 +561,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
// Configure transport-specific features.
if (transportType == HttpTransportType.LongPolling)
{
connection.Features.Set<IConnectionInherentKeepAliveFeature>(new ConnectionInherentKeepAliveFeature(options.LongPolling.PollTimeout));
connection.HasInherentKeepAlive = true;
// For long polling, the requests come and go but the connection is still alive.
// To make the IHttpContextFeature work well, we make a copy of the relevant properties

View File

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Client.Internal;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Extensions.DependencyInjection;
@ -719,7 +720,9 @@ namespace Microsoft.AspNetCore.SignalR.Client
{
// Check if we need keep-alive
Timer timeoutTimer = null;
if (connectionState.Connection.Features.Get<IConnectionInherentKeepAliveFeature>() == null)
// We use '!== true' because it could be null, which we treat as false.
if (connectionState.Connection.Features.Get<IConnectionInherentKeepAliveFeature>()?.HasInherentKeepAlive != true)
{
Log.StartingServerTimeoutTimer(_logger, ServerTimeout);
timeoutTimer = new Timer(

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.SignalR.Client
namespace Microsoft.AspNetCore.SignalR.Client.Internal
{
internal abstract class InvocationRequest : IDisposable
{

View File

@ -2,8 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.Serialization;
namespace Microsoft.AspNetCore.SignalR.Client
namespace Microsoft.AspNetCore.SignalR
{
[Serializable]
public class HubException : Exception
@ -19,5 +20,9 @@ namespace Microsoft.AspNetCore.SignalR.Client
public HubException(string message, Exception innerException) : base(message, innerException)
{
}
public HubException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

View File

@ -10,6 +10,8 @@
<ItemGroup>
<Compile Include="..\Common\JsonUtils.cs" Link="Internal\JsonUtils.cs" />
<Compile Include="..\Common\MemoryBufferWriter.cs" Link="Internal\MemoryBufferWriter.cs" />
<Compile Include="..\Common\TextMessageFormatter.cs" Link="Internal\TextMessageFormatter.cs" />
<Compile Include="..\Common\TextMessageParser.cs" Link="Internal\TextMessageParser.cs" />
<Compile Include="..\Common\Utf8BufferTextReader.cs" Link="Internal\Utf8BufferTextReader.cs" />
<Compile Include="..\Common\Utf8BufferTextWriter.cs" Link="Internal\Utf8BufferTextWriter.cs" />
</ItemGroup>

View File

@ -6,7 +6,6 @@ using System.Buffers;
using System.IO;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.SignalR.Protocol

View File

@ -5,7 +5,7 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.SignalR
{
public static class IClientProxyExtensions
public static class ClientProxyExtensions
{
/// <summary>
/// Invokes a method on the connection(s) represented by the <see cref="IClientProxy"/> instance.

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.SignalR
_logger = logger;
}
public override Task AddGroupAsync(string connectionId, string groupName)
public override Task AddToGroupAsync(string connectionId, string groupName)
{
if (connectionId == null)
{
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.SignalR
return Task.CompletedTask;
}
public override Task RemoveGroupAsync(string connectionId, string groupName)
public override Task RemoveFromGroupAsync(string connectionId, string groupName)
{
if (connectionId == null)
{
@ -219,7 +219,7 @@ namespace Microsoft.AspNetCore.SignalR
return Task.CompletedTask;
}
public override Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedIds)
public override Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
if (groupName == null)
{
@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.SignalR
List<Task> tasks = null;
SerializedHubMessage message = null;
SendToGroupConnections(methodName, args, group, connection => !excludedIds.Contains(connection.ConnectionId), ref tasks, ref message);
SendToGroupConnections(methodName, args, group, connection => !excludedConnectionIds.Contains(connection.ConnectionId), ref tasks, ref message);
if (tasks != null)
{
@ -271,9 +271,9 @@ namespace Microsoft.AspNetCore.SignalR
return Task.CompletedTask;
}
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedIds)
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
return SendToAllConnections(methodName, args, connection => !excludedIds.Contains(connection.ConnectionId));
return SendToAllConnections(methodName, args, connection => !excludedConnectionIds.Contains(connection.ConnectionId));
}
public override Task SendConnectionsAsync(IReadOnlyList<string> connectionIds, string methodName, object[] args)

View File

@ -16,13 +16,13 @@ namespace Microsoft.AspNetCore.SignalR
}
public dynamic All => new DynamicClientProxy(_clients.All);
public dynamic AllExcept(IReadOnlyList<string> excludedIds) => new DynamicClientProxy(_clients.AllExcept(excludedIds));
public dynamic AllExcept(IReadOnlyList<string> excludedConnectionIds) => new DynamicClientProxy(_clients.AllExcept(excludedConnectionIds));
public dynamic Caller => new DynamicClientProxy(_clients.Caller);
public dynamic Client(string connectionId) => new DynamicClientProxy(_clients.Client(connectionId));
public dynamic Clients(IReadOnlyList<string> connectionIds) => new DynamicClientProxy(_clients.Clients(connectionIds));
public dynamic Group(string groupName) => new DynamicClientProxy(_clients.Group(groupName));
public dynamic Groups(IReadOnlyList<string> groupNames) => new DynamicClientProxy(_clients.Groups(groupNames));
public dynamic GroupExcept(string groupName, IReadOnlyList<string> excludedIds) => new DynamicClientProxy(_clients.GroupExcept(groupName, excludedIds));
public dynamic GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds) => new DynamicClientProxy(_clients.GroupExcept(groupName, excludedConnectionIds));
public dynamic OthersInGroup(string groupName) => new DynamicClientProxy(_clients.OthersInGroup(groupName));
public dynamic Others => new DynamicClientProxy(_clients.Others);
public dynamic User(string userId) => new DynamicClientProxy(_clients.User(userId));

View File

@ -52,7 +52,8 @@ namespace Microsoft.AspNetCore.SignalR
public virtual IDictionary<object, object> Items => _connectionContext.Items;
public virtual PipeReader Input => _connectionContext.Transport.Input;
// Used by HubConnectionHandler
internal PipeReader Input => _connectionContext.Transport.Input;
public string UserIdentifier { get; set; }
@ -338,7 +339,8 @@ namespace Microsoft.AspNetCore.SignalR
UserIdentifier = userIdProvider.GetUserId(this);
if (Features.Get<IConnectionInherentKeepAliveFeature>() == null)
// != true needed because it could be null (which we treat as false)
if (Features.Get<IConnectionInherentKeepAliveFeature>()?.HasInherentKeepAlive != true)
{
// Only register KeepAlive after protocol handshake otherwise KeepAliveTick could try to write without having a ProtocolReaderWriter
Features.Get<IConnectionHeartbeatFeature>()?.OnHeartbeat(state => ((HubConnectionContext)state).KeepAliveTick(), this);

View File

@ -169,16 +169,18 @@ namespace Microsoft.AspNetCore.SignalR
try
{
var input = connection.Input;
var protocol = connection.Protocol;
while (true)
{
var result = await connection.Input.ReadAsync(connection.ConnectionAborted);
var result = await input.ReadAsync(connection.ConnectionAborted);
var buffer = result.Buffer;
try
{
if (!buffer.IsEmpty)
{
while (connection.Protocol.TryParseMessage(ref buffer, _dispatcher, out var message))
while (protocol.TryParseMessage(ref buffer, _dispatcher, out var message))
{
// Don't wait on the result of execution, continue processing other
// incoming messages on this connection.
@ -195,7 +197,7 @@ namespace Microsoft.AspNetCore.SignalR
// The buffer was sliced up to where it was consumed, so we can just advance to the start.
// We mark examined as buffer.End so that if we didn't receive a full frame, we'll wait for more data
// before yielding the read again.
connection.Input.AdvanceTo(buffer.Start, buffer.End);
input.AdvanceTo(buffer.Start, buffer.End);
}
}
}

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.SignalR
public abstract Task SendAllAsync(string methodName, object[] args);
public abstract Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedIds);
public abstract Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds);
public abstract Task SendConnectionAsync(string connectionId, string methodName, object[] args);
@ -24,15 +24,15 @@ namespace Microsoft.AspNetCore.SignalR
public abstract Task SendGroupsAsync(IReadOnlyList<string> groupNames, string methodName, object[] args);
public abstract Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedIds);
public abstract Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds);
public abstract Task SendUserAsync(string userId, string methodName, object[] args);
public abstract Task SendUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args);
public abstract Task AddGroupAsync(string connectionId, string groupName);
public abstract Task AddToGroupAsync(string connectionId, string groupName);
public abstract Task RemoveGroupAsync(string connectionId, string groupName);
public abstract Task RemoveFromGroupAsync(string connectionId, string groupName);
}
}

View File

@ -1,6 +1,8 @@
// 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 Microsoft.AspNetCore.SignalR.Internal;
namespace Microsoft.AspNetCore.SignalR
{
public class Hub<T> : Hub where T : class

View File

@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.SignalR
{
public interface IGroupManager
{
Task AddAsync(string connectionId, string groupName);
Task RemoveAsync(string connectionId, string groupName);
Task AddToGroupAsync(string connectionId, string groupName);
Task RemoveFromGroupAsync(string connectionId, string groupName);
}
}

View File

@ -0,0 +1,558 @@
// 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.Collections.Generic;
namespace Microsoft.AspNetCore.SignalR
{
public static class IHubClientsExtensions
{
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1)
{
return hubClients.AllExcept(new [] { excludedConnectionId1 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <param name="excludedConnectionId6">The sixth connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <param name="excludedConnectionId6">The sixth connection to exclude.</param>
/// <param name="excludedConnectionId7">The seventh connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6, string excludedConnectionId7)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6, excludedConnectionId7 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <param name="excludedConnectionId6">The sixth connection to exclude.</param>
/// <param name="excludedConnectionId7">The seventh connection to exclude.</param>
/// <param name="excludedConnectionId8">The eighth connection to exclude.</param>
/// <returns></returns>
public static T AllExcept<T>(this IHubClients<T> hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6, string excludedConnectionId7, string excludedConnectionId8)
{
return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6, excludedConnectionId7, excludedConnectionId8 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1)
{
return hubClients.Clients(new [] { connection1 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2)
{
return hubClients.Clients(new [] { connection1, connection2 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <param name="connection3">The third connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2, string connection3)
{
return hubClients.Clients(new [] { connection1, connection2, connection3 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <param name="connection3">The third connection to include.</param>
/// <param name="connection4">The fourth connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2, string connection3, string connection4)
{
return hubClients.Clients(new [] { connection1, connection2, connection3, connection4 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <param name="connection3">The third connection to include.</param>
/// <param name="connection4">The fourth connection to include.</param>
/// <param name="connection5">The fifth connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2, string connection3, string connection4, string connection5)
{
return hubClients.Clients(new [] { connection1, connection2, connection3, connection4, connection5 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <param name="connection3">The third connection to include.</param>
/// <param name="connection4">The fourth connection to include.</param>
/// <param name="connection5">The fifth connection to include.</param>
/// <param name="connection6">The sixth connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2, string connection3, string connection4, string connection5, string connection6)
{
return hubClients.Clients(new [] { connection1, connection2, connection3, connection4, connection5, connection6 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <param name="connection3">The third connection to include.</param>
/// <param name="connection4">The fourth connection to include.</param>
/// <param name="connection5">The fifth connection to include.</param>
/// <param name="connection6">The sixth connection to include.</param>
/// <param name="connection7">The seventh connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2, string connection3, string connection4, string connection5, string connection6, string connection7)
{
return hubClients.Clients(new [] { connection1, connection2, connection3, connection4, connection5, connection6, connection7 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="connection1">The first connection to include.</param>
/// <param name="connection2">The second connection to include.</param>
/// <param name="connection3">The third connection to include.</param>
/// <param name="connection4">The fourth connection to include.</param>
/// <param name="connection5">The fifth connection to include.</param>
/// <param name="connection6">The sixth connection to include.</param>
/// <param name="connection7">The seventh connection to include.</param>
/// <param name="connection8">The eighth connection to include.</param>
/// <returns></returns>
public static T Clients<T>(this IHubClients<T> hubClients, string connection1, string connection2, string connection3, string connection4, string connection5, string connection6, string connection7, string connection8)
{
return hubClients.Clients(new [] { connection1, connection2, connection3, connection4, connection5, connection6, connection7, connection8 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1)
{
return hubClients.Groups(new [] { group1 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2)
{
return hubClients.Groups(new [] { group1, group2 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <param name="group3">The third group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2, string group3)
{
return hubClients.Groups(new [] { group1, group2, group3 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <param name="group3">The third group to include.</param>
/// <param name="group4">The fourth group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2, string group3, string group4)
{
return hubClients.Groups(new [] { group1, group2, group3, group4 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <param name="group3">The third group to include.</param>
/// <param name="group4">The fourth group to include.</param>
/// <param name="group5">The fifth group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2, string group3, string group4, string group5)
{
return hubClients.Groups(new [] { group1, group2, group3, group4, group5 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <param name="group3">The third group to include.</param>
/// <param name="group4">The fourth group to include.</param>
/// <param name="group5">The fifth group to include.</param>
/// <param name="group6">The sixth group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2, string group3, string group4, string group5, string group6)
{
return hubClients.Groups(new [] { group1, group2, group3, group4, group5, group6 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <param name="group3">The third group to include.</param>
/// <param name="group4">The fourth group to include.</param>
/// <param name="group5">The fifth group to include.</param>
/// <param name="group6">The sixth group to include.</param>
/// <param name="group7">The seventh group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2, string group3, string group4, string group5, string group6, string group7)
{
return hubClients.Groups(new [] { group1, group2, group3, group4, group5, group6, group7 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="group1">The first group to include.</param>
/// <param name="group2">The second group to include.</param>
/// <param name="group3">The third group to include.</param>
/// <param name="group4">The fourth group to include.</param>
/// <param name="group5">The fifth group to include.</param>
/// <param name="group6">The sixth group to include.</param>
/// <param name="group7">The seventh group to include.</param>
/// <param name="group8">The eighth group to include.</param>
/// <returns></returns>
public static T Groups<T>(this IHubClients<T> hubClients, string group1, string group2, string group3, string group4, string group5, string group6, string group7, string group8)
{
return hubClients.Groups(new [] { group1, group2, group3, group4, group5, group6, group7, group8 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <param name="excludedConnectionId6">The sixth connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <param name="excludedConnectionId6">The sixth connection to exclude.</param>
/// <param name="excludedConnectionId7">The seventh connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6, string excludedConnectionId7)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6, excludedConnectionId7 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="groupName"></param>
/// <param name="excludedConnectionId1">The first connection to exclude.</param>
/// <param name="excludedConnectionId2">The second connection to exclude.</param>
/// <param name="excludedConnectionId3">The third connection to exclude.</param>
/// <param name="excludedConnectionId4">The fourth connection to exclude.</param>
/// <param name="excludedConnectionId5">The fifth connection to exclude.</param>
/// <param name="excludedConnectionId6">The sixth connection to exclude.</param>
/// <param name="excludedConnectionId7">The seventh connection to exclude.</param>
/// <param name="excludedConnectionId8">The eighth connection to exclude.</param>
/// <returns></returns>
public static T GroupExcept<T>(this IHubClients<T> hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6, string excludedConnectionId7, string excludedConnectionId8)
{
return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6, excludedConnectionId7, excludedConnectionId8 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1)
{
return hubClients.Users(new [] { user1 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2)
{
return hubClients.Users(new [] { user1, user2 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <param name="user3">The third user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2, string user3)
{
return hubClients.Users(new [] { user1, user2, user3 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <param name="user3">The third user to include.</param>
/// <param name="user4">The fourth user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2, string user3, string user4)
{
return hubClients.Users(new [] { user1, user2, user3, user4 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <param name="user3">The third user to include.</param>
/// <param name="user4">The fourth user to include.</param>
/// <param name="user5">The fifth user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2, string user3, string user4, string user5)
{
return hubClients.Users(new [] { user1, user2, user3, user4, user5 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <param name="user3">The third user to include.</param>
/// <param name="user4">The fourth user to include.</param>
/// <param name="user5">The fifth user to include.</param>
/// <param name="user6">The sixth user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2, string user3, string user4, string user5, string user6)
{
return hubClients.Users(new [] { user1, user2, user3, user4, user5, user6 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <param name="user3">The third user to include.</param>
/// <param name="user4">The fourth user to include.</param>
/// <param name="user5">The fifth user to include.</param>
/// <param name="user6">The sixth user to include.</param>
/// <param name="user7">The seventh user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2, string user3, string user4, string user5, string user6, string user7)
{
return hubClients.Users(new [] { user1, user2, user3, user4, user5, user6, user7 });
}
/// <summary>
/// </summary>
/// <param name="hubClients"></param>
/// <param name="user1">The first user to include.</param>
/// <param name="user2">The second user to include.</param>
/// <param name="user3">The third user to include.</param>
/// <param name="user4">The fourth user to include.</param>
/// <param name="user5">The fifth user to include.</param>
/// <param name="user6">The sixth user to include.</param>
/// <param name="user7">The seventh user to include.</param>
/// <param name="user8">The eighth user to include.</param>
/// <returns></returns>
public static T Users<T>(this IHubClients<T> hubClients, string user1, string user2, string user3, string user4, string user5, string user6, string user7, string user8)
{
return hubClients.Users(new [] { user1, user2, user3, user4, user5, user6, user7, user8 });
}
}
}

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.SignalR
{
T All { get; }
T AllExcept(IReadOnlyList<string> excludedIds);
T AllExcept(IReadOnlyList<string> excludedConnectionIds);
T Client(string connectionId);
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.SignalR
T Groups(IReadOnlyList<string> groupNames);
T GroupExcept(string groupName, IReadOnlyList<string> excludeIds);
T GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds);
T User(string userId);

View File

@ -5,7 +5,7 @@ using System;
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.SignalR
namespace Microsoft.AspNetCore.SignalR.Internal
{
public class DefaultHubActivator<THub> : IHubActivator<THub> where THub: Hub
{
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.SignalR
_serviceProvider = serviceProvider;
}
public THub Create()
public virtual THub Create()
{
Debug.Assert(!_created.HasValue, "hub activators must not be reused.");
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.SignalR
return hub;
}
public void Release(THub hub)
public virtual void Release(THub hub)
{
if (hub == null)
{

View File

@ -8,7 +8,7 @@ using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.SignalR
namespace Microsoft.AspNetCore.SignalR.Internal
{
public class DefaultHubCallerContext : HubCallerContext
{

View File

@ -24,9 +24,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
public IClientProxy All => _hubClients.All;
public IClientProxy AllExcept(IReadOnlyList<string> excludedIds)
public IClientProxy AllExcept(IReadOnlyList<string> excludedConnectionIds)
{
return _hubClients.AllExcept(excludedIds);
return _hubClients.AllExcept(excludedConnectionIds);
}
public IClientProxy Client(string connectionId)
@ -49,9 +49,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return _hubClients.GroupExcept(groupName, _currentConnectionId);
}
public IClientProxy GroupExcept(string groupName, IReadOnlyList<string> excludeIds)
public IClientProxy GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds)
{
return _hubClients.GroupExcept(groupName, excludeIds);
return _hubClients.GroupExcept(groupName, excludedConnectionIds);
}
public IClientProxy User(string userId)

View File

@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
public IClientProxy All { get; }
public IClientProxy AllExcept(IReadOnlyList<string> excludedIds)
public IClientProxy AllExcept(IReadOnlyList<string> excludedConnectionIds)
{
return new AllClientsExceptProxy<THub>(_lifetimeManager, excludedIds);
return new AllClientsExceptProxy<THub>(_lifetimeManager, excludedConnectionIds);
}
public IClientProxy Client(string connectionId)
@ -32,9 +32,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return new GroupProxy<THub>(_lifetimeManager, groupName);
}
public IClientProxy GroupExcept(string groupName, IReadOnlyList<string> excludeIds)
public IClientProxy GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds)
{
return new GroupExceptProxy<THub>(_lifetimeManager, groupName, excludeIds);
return new GroupExceptProxy<THub>(_lifetimeManager, groupName, excludedConnectionIds);
}
public IClientProxy Clients(IReadOnlyList<string> connectionIds)

View File

@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
public T All { get; }
public T AllExcept(IReadOnlyList<string> excludedIds)
public T AllExcept(IReadOnlyList<string> excludedConnectionIds)
{
return TypedClientBuilder<T>.Build(new AllClientsExceptProxy<THub>(_lifetimeManager, excludedIds));
return TypedClientBuilder<T>.Build(new AllClientsExceptProxy<THub>(_lifetimeManager, excludedConnectionIds));
}
public virtual T Client(string connectionId)
@ -37,9 +37,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return TypedClientBuilder<T>.Build(new GroupProxy<THub>(_lifetimeManager, groupName));
}
public T GroupExcept(string groupName, IReadOnlyList<string> excludeIds)
public T GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds)
{
return TypedClientBuilder<T>.Build(new GroupExceptProxy<THub>(_lifetimeManager, groupName, excludeIds));
return TypedClientBuilder<T>.Build(new GroupExceptProxy<THub>(_lifetimeManager, groupName, excludedConnectionIds));
}
public T Groups(IReadOnlyList<string> groupNames)

View File

@ -78,18 +78,18 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{
private readonly string _groupName;
private readonly HubLifetimeManager<THub> _lifetimeManager;
private readonly IReadOnlyList<string> _excludedIds;
private readonly IReadOnlyList<string> _excludedConnectionIds;
public GroupExceptProxy(HubLifetimeManager<THub> lifetimeManager, string groupName, IReadOnlyList<string> excludedIds)
public GroupExceptProxy(HubLifetimeManager<THub> lifetimeManager, string groupName, IReadOnlyList<string> excludedConnectionIds)
{
_lifetimeManager = lifetimeManager;
_groupName = groupName;
_excludedIds = excludedIds;
_excludedConnectionIds = excludedConnectionIds;
}
public Task SendCoreAsync(string method, object[] args)
{
return _lifetimeManager.SendGroupExceptAsync(_groupName, method, args, _excludedIds);
return _lifetimeManager.SendGroupExceptAsync(_groupName, method, args, _excludedConnectionIds);
}
}
@ -111,17 +111,17 @@ namespace Microsoft.AspNetCore.SignalR.Internal
internal class AllClientsExceptProxy<THub> : IClientProxy where THub : Hub
{
private readonly HubLifetimeManager<THub> _lifetimeManager;
private readonly IReadOnlyList<string> _excludedIds;
private readonly IReadOnlyList<string> _excludedConnectionIds;
public AllClientsExceptProxy(HubLifetimeManager<THub> lifetimeManager, IReadOnlyList<string> excludedIds)
public AllClientsExceptProxy(HubLifetimeManager<THub> lifetimeManager, IReadOnlyList<string> excludedConnectionIds)
{
_lifetimeManager = lifetimeManager;
_excludedIds = excludedIds;
_excludedConnectionIds = excludedConnectionIds;
}
public Task SendCoreAsync(string method, object[] args)
{
return _lifetimeManager.SendAllExceptAsync(method, args, _excludedIds);
return _lifetimeManager.SendAllExceptAsync(method, args, _excludedConnectionIds);
}
}
@ -168,14 +168,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal
_lifetimeManager = lifetimeManager;
}
public Task AddAsync(string connectionId, string groupName)
public Task AddToGroupAsync(string connectionId, string groupName)
{
return _lifetimeManager.AddGroupAsync(connectionId, groupName);
return _lifetimeManager.AddToGroupAsync(connectionId, groupName);
}
public Task RemoveAsync(string connectionId, string groupName)
public Task RemoveFromGroupAsync(string connectionId, string groupName)
{
return _lifetimeManager.RemoveGroupAsync(connectionId, groupName);
return _lifetimeManager.RemoveFromGroupAsync(connectionId, groupName);
}
}
}

View File

@ -1,7 +1,7 @@
// 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
namespace Microsoft.AspNetCore.SignalR.Internal
{
internal class SignalRMarkerService
{

View File

@ -9,7 +9,7 @@ using System.Reflection;
using System.Reflection.Emit;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.SignalR
namespace Microsoft.AspNetCore.SignalR.Internal
{
internal static class TypedClientBuilder<T>
{

View File

@ -3,7 +3,7 @@
using System.Collections.Generic;
namespace Microsoft.AspNetCore.SignalR
namespace Microsoft.AspNetCore.SignalR.Internal
{
internal class TypedHubClients<T> : IHubCallerClients<T>
{
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.SignalR
public T Others => TypedClientBuilder<T>.Build(_hubClients.Others);
public T AllExcept(IReadOnlyList<string> excludedIds) => TypedClientBuilder<T>.Build(_hubClients.AllExcept(excludedIds));
public T AllExcept(IReadOnlyList<string> excludedConnectionIds) => TypedClientBuilder<T>.Build(_hubClients.AllExcept(excludedConnectionIds));
public T Client(string connectionId)
{
@ -32,9 +32,9 @@ namespace Microsoft.AspNetCore.SignalR
return TypedClientBuilder<T>.Build(_hubClients.Group(groupName));
}
public T GroupExcept(string groupName, IReadOnlyList<string> excludeIds)
public T GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds)
{
return TypedClientBuilder<T>.Build(_hubClients.GroupExcept(groupName, excludeIds));
return TypedClientBuilder<T>.Build(_hubClients.GroupExcept(groupName, excludedConnectionIds));
}
public T Clients(IReadOnlyList<string> connectionIds)

View File

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.SignalR.Protocol;
namespace Microsoft.AspNetCore.SignalR.Internal
namespace Microsoft.AspNetCore.SignalR
{
/// <summary>
/// This class is designed to support the framework. The API is subject to breaking changes.

View File

@ -3,7 +3,7 @@
using System;
namespace Microsoft.AspNetCore.SignalR.Internal
namespace Microsoft.AspNetCore.SignalR
{
public readonly struct SerializedMessage
{

View File

@ -3,6 +3,7 @@
using System;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.SignalR

View File

@ -9,6 +9,8 @@
<ItemGroup>
<Compile Include="..\Common\JsonUtils.cs" Link="Internal\JsonUtils.cs" />
<Compile Include="..\Common\TextMessageFormatter.cs" Link="TextMessageFormatter.cs" />
<Compile Include="..\Common\TextMessageParser.cs" Link="TextMessageParser.cs" />
<Compile Include="..\Common\Utf8BufferTextReader.cs" Link="Utf8BufferTextReader.cs" />
<Compile Include="..\Common\Utf8BufferTextWriter.cs" Link="Utf8BufferTextWriter.cs" />
</ItemGroup>

View File

@ -9,7 +9,6 @@ using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

View File

@ -8,6 +8,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Common\BinaryMessageFormatter.cs" Link="BinaryMessageFormatter.cs" />
<Compile Include="..\Common\BinaryMessageParser.cs" Link="BinaryMessageParser.cs" />
<Compile Include="..\Common\MemoryBufferWriter.cs" Link="Internal\MemoryBufferWriter.cs" />
</ItemGroup>

View File

@ -12,7 +12,6 @@ using MessagePack;
using MessagePack.Formatters;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.SignalR.Protocol

View File

@ -10,24 +10,24 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Internal
/// Gets a list of connections that should be excluded from this invocation.
/// May be null to indicate that no connections are to be excluded.
/// </summary>
public IReadOnlyList<string> ExcludedIds { get; }
public IReadOnlyList<string> ExcludedConnectionIds { get; }
/// <summary>
/// Gets the message serialization cache containing serialized payloads for the message.
/// </summary>
public SerializedHubMessage Message { get; }
public RedisInvocation(SerializedHubMessage message, IReadOnlyList<string> excludedIds)
public RedisInvocation(SerializedHubMessage message, IReadOnlyList<string> excludedConnectionIds)
{
Message = message;
ExcludedIds = excludedIds;
ExcludedConnectionIds = excludedConnectionIds;
}
public static RedisInvocation Create(string target, object[] arguments, IReadOnlyList<string> excludedIds = null)
public static RedisInvocation Create(string target, object[] arguments, IReadOnlyList<string> excludedConnectionIds = null)
{
return new RedisInvocation(
new SerializedHubMessage(new InvocationMessage(target, null, arguments)),
excludedIds);
excludedConnectionIds);
}
}
}

View File

@ -6,7 +6,7 @@ using System.Linq;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace Microsoft.AspNetCore.SignalR.Redis
namespace Microsoft.AspNetCore.SignalR.Redis.Internal
{
// We don't want to use our nested static class here because RedisHubLifetimeManager is generic.
// We'd end up creating separate instances of all the LoggerMessage.Define values for each Hub.

View File

@ -10,7 +10,6 @@ using MessagePack;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Protocol;
using StackExchange.Redis;
namespace Microsoft.AspNetCore.SignalR.Redis.Internal
{
@ -35,9 +34,9 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Internal
// * A 7-bit variable length integer encodes the length in bytes, followed by the encoded string in UTF-8.
public byte[] WriteInvocation(string methodName, object[] args) =>
WriteInvocation(methodName, args, excludedIds: null);
WriteInvocation(methodName, args, excludedConnectionIds: null);
public byte[] WriteInvocation(string methodName, object[] args, IReadOnlyList<string> excludedIds)
public byte[] WriteInvocation(string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
// Written as a MessagePack 'arr' containing at least these items:
// * A MessagePack 'arr' of 'str's representing the excluded ids
@ -49,10 +48,10 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Internal
try
{
MessagePackBinary.WriteArrayHeader(writer, 2);
if (excludedIds != null && excludedIds.Count > 0)
if (excludedConnectionIds != null && excludedConnectionIds.Count > 0)
{
MessagePackBinary.WriteArrayHeader(writer, excludedIds.Count);
foreach (var id in excludedIds)
MessagePackBinary.WriteArrayHeader(writer, excludedConnectionIds.Count);
foreach (var id in excludedConnectionIds)
{
MessagePackBinary.WriteString(writer, id);
}
@ -126,7 +125,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Internal
ValidateArraySize(ref data, 2, "Invocation");
// Read excluded Ids
IReadOnlyList<string> excludedIds = null;
IReadOnlyList<string> excludedConnectionIds = null;
var idCount = MessagePackUtil.ReadArrayHeader(ref data);
if (idCount > 0)
{
@ -136,12 +135,12 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Internal
ids[i] = MessagePackUtil.ReadString(ref data);
}
excludedIds = ids;
excludedConnectionIds = ids;
}
// Read payload
var message = ReadSerializedHubMessage(ref data);
return new RedisInvocation(message, excludedIds);
return new RedisInvocation(message, excludedConnectionIds);
}
public RedisGroupCommand ReadGroupCommand(ReadOnlyMemory<byte> data)

View File

@ -19,7 +19,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
return AddRedis(builder, o =>
{
o.Options = ConfigurationOptions.Parse(redisConnectionString);
o.Configuration = ConfigurationOptions.Parse(redisConnectionString);
});
}
@ -34,7 +34,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
return AddRedis(builder, o =>
{
o.Options = ConfigurationOptions.Parse(redisConnectionString);
o.Configuration = ConfigurationOptions.Parse(redisConnectionString);
configure(o);
});
}

View File

@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
_channels = new RedisChannels(typeof(THub).FullName);
_protocol = new RedisProtocol(hubProtocolResolver.AllProtocols);
RedisLog.ConnectingToEndpoints(_logger, options.Value.Options.EndPoints, _serverName);
RedisLog.ConnectingToEndpoints(_logger, options.Value.Configuration.EndPoints, _serverName);
_ = EnsureRedisServerConnection();
}
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
if (groupNames != null)
{
// Copy the groups to an array here because they get removed from this collection
// in RemoveGroupAsync
// in RemoveFromGroupAsync
foreach (var group in groupNames.ToArray())
{
// Use RemoveGroupAsyncCore because the connection is local and we don't want to
@ -112,9 +112,9 @@ namespace Microsoft.AspNetCore.SignalR.Redis
return PublishAsync(_channels.All, message);
}
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedIds)
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
var message = _protocol.WriteInvocation(methodName, args, excludedIds);
var message = _protocol.WriteInvocation(methodName, args, excludedConnectionIds);
return PublishAsync(_channels.All, message);
}
@ -148,14 +148,14 @@ namespace Microsoft.AspNetCore.SignalR.Redis
return PublishAsync(_channels.Group(groupName), message);
}
public override async Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedIds)
public override async Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds)
{
if (groupName == null)
{
throw new ArgumentNullException(nameof(groupName));
}
var message = _protocol.WriteInvocation(methodName, args, excludedIds);
var message = _protocol.WriteInvocation(methodName, args, excludedConnectionIds);
await PublishAsync(_channels.Group(groupName), message);
}
@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
return PublishAsync(_channels.User(userId), message);
}
public override async Task AddGroupAsync(string connectionId, string groupName)
public override async Task AddToGroupAsync(string connectionId, string groupName)
{
if (connectionId == null)
{
@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
await SendGroupActionAndWaitForAck(connectionId, groupName, GroupAction.Add);
}
public override async Task RemoveGroupAsync(string connectionId, string groupName)
public override async Task RemoveFromGroupAsync(string connectionId, string groupName)
{
if (connectionId == null)
{
@ -388,7 +388,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
foreach (var connection in _connections)
{
if (invocation.ExcludedIds == null || !invocation.ExcludedIds.Contains(connection.ConnectionId))
if (invocation.ExcludedConnectionIds == null || !invocation.ExcludedConnectionIds.Contains(connection.ConnectionId))
{
tasks.Add(connection.WriteAsync(invocation.Message).AsTask());
}
@ -487,7 +487,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
var tasks = new List<Task>();
foreach (var groupConnection in group.Connections)
{
if (invocation.ExcludedIds?.Contains(groupConnection.ConnectionId) == true)
if (invocation.ExcludedConnectionIds?.Contains(groupConnection.ConnectionId) == true)
{
continue;
}

View File

@ -11,31 +11,31 @@ namespace Microsoft.AspNetCore.SignalR.Redis
{
public class RedisOptions
{
public ConfigurationOptions Options { get; set; } = new ConfigurationOptions
public ConfigurationOptions Configuration { get; set; } = new ConfigurationOptions
{
// Enable reconnecting by default
AbortOnConnectFail = false
};
public Func<TextWriter, Task<IConnectionMultiplexer>> Factory { get; set; }
public Func<TextWriter, Task<IConnectionMultiplexer>> ConnectionFactory { get; set; }
internal async Task<IConnectionMultiplexer> ConnectAsync(TextWriter log)
{
// Factory is publically settable. Assigning to a local variable before null check for thread safety.
var localFactory = Factory;
if (localFactory == null)
var factory = ConnectionFactory;
if (factory == null)
{
// REVIEW: Should we do this?
if (Options.EndPoints.Count == 0)
if (Configuration.EndPoints.Count == 0)
{
Options.EndPoints.Add(IPAddress.Loopback, 0);
Options.SetDefaultPorts();
Configuration.EndPoints.Add(IPAddress.Loopback, 0);
Configuration.SetDefaultPorts();
}
return await ConnectionMultiplexer.ConnectAsync(Options, log);
return await ConnectionMultiplexer.ConnectAsync(Configuration, log);
}
return await localFactory(log);
return await factory(log);
}
}
}

View File

@ -18,11 +18,6 @@ namespace Microsoft.AspNetCore.SignalR
_routes = routes;
}
public void MapHub<THub>(string path) where THub : Hub
{
MapHub<THub>(new PathString(path), configureOptions: null);
}
public void MapHub<THub>(PathString path) where THub : Hub
{
MapHub<THub>(path, configureOptions: null);

View File

@ -636,6 +636,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
// Start a poll
var task = dispatcher.ExecuteAsync(context, new HttpConnectionDispatcherOptions(), app);
Assert.True(task.IsCompleted);
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
task = dispatcher.ExecuteAsync(context, new HttpConnectionDispatcherOptions(), app);
// Send to the application
var buffer = Encoding.UTF8.GetBytes("Hello World");
@ -745,7 +749,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
}
[Theory]
[InlineData(HttpTransportType.LongPolling, 204)]
[InlineData(HttpTransportType.LongPolling, 200)]
[InlineData(HttpTransportType.WebSockets, 404)]
[InlineData(HttpTransportType.ServerSentEvents, 404)]
public async Task EndPointThatOnlySupportsLongPollingRejectsOtherTransports(HttpTransportType transportType, int status)
@ -869,6 +873,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
var builder = new ConnectionBuilder(services.BuildServiceProvider());
builder.UseConnectionHandler<ImmediatelyCompleteConnectionHandler>();
var app = builder.Build();
// First poll will 200
await dispatcher.ExecuteAsync(context, new HttpConnectionDispatcherOptions(), app);
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
await dispatcher.ExecuteAsync(context, new HttpConnectionDispatcherOptions(), app);
Assert.Equal(StatusCodes.Status204NoContent, context.Response.StatusCode);
@ -998,6 +1006,9 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
var app = builder.Build();
var options = new HttpConnectionDispatcherOptions();
var request1 = dispatcher.ExecuteAsync(context1, options, app);
Assert.True(request1.IsCompleted);
request1 = dispatcher.ExecuteAsync(context1, options, app);
var request2 = dispatcher.ExecuteAsync(context2, options, app);
await request1;
@ -1132,7 +1143,14 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
builder.UseConnectionHandler<BlockingConnectionHandler>();
var app = builder.Build();
var options = new HttpConnectionDispatcherOptions();
// Initial poll
var task = dispatcher.ExecuteAsync(context, options, app);
Assert.True(task.IsCompleted);
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
// Real long running poll
task = dispatcher.ExecuteAsync(context, options, app);
var buffer = Encoding.UTF8.GetBytes("Hello World");
@ -1166,7 +1184,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
var options = new HttpConnectionDispatcherOptions();
var context1 = MakeRequest("/foo", connection);
// This is the initial poll to make sure things are setup
var task1 = dispatcher.ExecuteAsync(context1, options, app);
Assert.True(task1.IsCompleted);
task1 = dispatcher.ExecuteAsync(context1, options, app);
var context2 = MakeRequest("/foo", connection);
var task2 = dispatcher.ExecuteAsync(context2, options, app);
@ -1363,10 +1384,13 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
context.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "name") }));
var connectionHandlerTask = dispatcher.ExecuteAsync(context, options, app);
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello, World")).AsTask().OrTimeout();
await connectionHandlerTask.OrTimeout();
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
connectionHandlerTask = dispatcher.ExecuteAsync(context, options, app);
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello, World")).AsTask().OrTimeout();
await connectionHandlerTask.OrTimeout();
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
Assert.Equal("Hello, World", GetContentAsString(context.Response.Body));
}
@ -1444,7 +1468,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
new Claim(ClaimTypes.StreetAddress, "12345 123rd St. NW")
}));
// First poll
var connectionHandlerTask = dispatcher.ExecuteAsync(context, options, app);
Assert.True(connectionHandlerTask.IsCompleted);
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
connectionHandlerTask = dispatcher.ExecuteAsync(context, options, app);
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello, World")).AsTask().OrTimeout();
await connectionHandlerTask.OrTimeout();
@ -1502,7 +1531,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
// "authorize" user
context.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "name") }));
// Initial poll
var connectionHandlerTask = dispatcher.ExecuteAsync(context, options, app);
Assert.True(connectionHandlerTask.IsCompleted);
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
connectionHandlerTask = dispatcher.ExecuteAsync(context, options, app);
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello, World")).AsTask().OrTimeout();
await connectionHandlerTask.OrTimeout();
@ -1587,12 +1621,12 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
var options = new HttpConnectionDispatcherOptions();
options.LongPolling.PollTimeout = TimeSpan.FromMilliseconds(1); // We don't care about the poll itself
Assert.Null(connection.Features.Get<IConnectionInherentKeepAliveFeature>());
await dispatcher.ExecuteAsync(context, options, app).OrTimeout();
Assert.NotNull(connection.Features.Get<IConnectionInherentKeepAliveFeature>());
Assert.Equal(options.LongPolling.PollTimeout, connection.Features.Get<IConnectionInherentKeepAliveFeature>().KeepAliveInterval);
Assert.True(connection.HasInherentKeepAlive);
// Check via the feature as well to make sure it's there.
Assert.True(connection.Features.Get<IConnectionInherentKeepAliveFeature>().HasInherentKeepAlive);
}
}
@ -1660,6 +1694,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
var options = new HttpConnectionDispatcherOptions();
var pollTask = dispatcher.ExecuteAsync(context, options, app);
Assert.True(pollTask.IsCompleted);
// Now send the second poll
pollTask = dispatcher.ExecuteAsync(context, options, app);
// Issue the delete request and make sure the poll completes
var deleteContext = new DefaultHttpContext();

View File

@ -7,9 +7,9 @@ using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.AspNetCore.Http.Connections.Client.Internal;
using Microsoft.AspNetCore.Http.Connections.Internal;
using Microsoft.AspNetCore.SignalR.Tests;
using Microsoft.Extensions.Logging.Testing;
using Xunit;

View File

@ -9,17 +9,24 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.AspNetCore.Http.Connections.Client.Internal;
using Microsoft.AspNetCore.SignalR.Tests;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
public partial class HttpConnectionTests
{
public class Transport
public class Transport : VerifiableLoggedTest
{
public Transport(ITestOutputHelper output) : base(output)
{
}
[Theory]
[InlineData(HttpTransportType.LongPolling)]
[InlineData(HttpTransportType.ServerSentEvents)]
@ -29,11 +36,6 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var requestsExecuted = false;
var callCount = 0;
testHttpHandler.OnRequest((request, next, token) =>
{
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
});
testHttpHandler.OnNegotiate((_, cancellationToken) =>
{
return ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent());
@ -51,6 +53,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
return await next();
});
testHttpHandler.OnRequest((request, next, token) =>
{
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
});
Task<string> AccessTokenProvider()
{
callCount++;
@ -69,6 +76,32 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
Assert.True(requestsExecuted);
}
[Theory]
[InlineData(HttpTransportType.LongPolling, true)]
[InlineData(HttpTransportType.ServerSentEvents, false)]
public async Task HttpConnectionSetsInherentKeepAliveFeature(HttpTransportType transportType, bool expectedValue)
{
using (StartVerifableLog(out var loggerFactory, testName: $"HttpConnectionSetsInherentKeepAliveFeature_{transportType}_{expectedValue}"))
{
var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
testHttpHandler.OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));
testHttpHandler.OnRequest((request, next, token) => Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)));
await WithConnectionAsync(
CreateConnection(testHttpHandler, transportType: transportType, loggerFactory: loggerFactory),
async (connection) =>
{
await connection.StartAsync(TransferFormat.Text).OrTimeout();
var feature = connection.Features.Get<IConnectionInherentKeepAliveFeature>();
Assert.NotNull(feature);
Assert.Equal(expectedValue, feature.HasInherentKeepAlive);
});
}
}
[Theory]
[InlineData(HttpTransportType.LongPolling)]
[InlineData(HttpTransportType.ServerSentEvents)]
@ -77,10 +110,6 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
var requestsExecuted = false;
testHttpHandler.OnRequest((request, next, token) =>
{
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
});
testHttpHandler.OnNegotiate((_, cancellationToken) =>
{
@ -105,6 +134,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
return await next();
});
testHttpHandler.OnRequest((request, next, token) =>
{
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
});
await WithConnectionAsync(
CreateConnection(testHttpHandler, transportType: transportType),
async (connection) =>
@ -124,11 +158,6 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
var requestsExecuted = false;
testHttpHandler.OnRequest((request, next, token) =>
{
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
});
testHttpHandler.OnNegotiate((_, cancellationToken) =>
{
return ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent());
@ -145,6 +174,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
return await next();
});
testHttpHandler.OnRequest((request, next, token) =>
{
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
});
await WithConnectionAsync(
CreateConnection(testHttpHandler, transportType: transportType),
async (connection) =>

View File

@ -109,15 +109,20 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
if (requests == 0)
{
requests++;
return ResponseUtils.CreateResponse(HttpStatusCode.OK, "Hello");
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
else if (requests == 1)
{
requests++;
return ResponseUtils.CreateResponse(HttpStatusCode.OK, "Hello");
}
else if (requests == 2)
{
requests++;
// Time out
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
else if (requests == 2)
else if (requests == 3)
{
requests++;
return ResponseUtils.CreateResponse(HttpStatusCode.OK, "World");
@ -147,7 +152,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
}
[Fact]
public async Task LongPollingTransportStopsWhenPollRequestFails()
public async Task LongPollingTransportStartAsyncFailsIfFirstRequestFails()
{
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
@ -158,6 +163,39 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
return ResponseUtils.CreateResponse(HttpStatusCode.InternalServerError);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var longPollingTransport = new LongPollingTransport(httpClient);
try
{
var exception = await Assert.ThrowsAsync<HttpRequestException>(() => longPollingTransport.StartAsync(TestUri, TransferFormat.Binary));
Assert.Contains(" 500 ", exception.Message);
}
finally
{
await longPollingTransport.StopAsync();
}
}
}
[Fact]
public async Task LongPollingTransportStopsWhenPollRequestFails()
{
var mockHttpHandler = new Mock<HttpMessageHandler>();
var firstPoll = true;
mockHttpHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
{
await Task.Yield();
if (firstPoll)
{
firstPoll = false;
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
return ResponseUtils.CreateResponse(HttpStatusCode.InternalServerError);
});
using (var httpClient = new HttpClient(mockHttpHandler.Object))
{
var longPollingTransport = new LongPollingTransport(httpClient);
@ -314,7 +352,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
var message1Payload = new[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o' };
var firstCall = true;
var requests = 0;
var mockHttpHandler = new Mock<HttpMessageHandler>();
var sentRequests = new List<HttpRequestMessage>();
mockHttpHandler.Protected()
@ -325,9 +363,14 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
await Task.Yield();
if (firstCall)
if (requests == 0)
{
firstCall = false;
requests++;
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
else if (requests == 1)
{
requests++;
return ResponseUtils.CreateResponse(HttpStatusCode.OK, message1Payload);
}
@ -349,7 +392,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var message = await longPollingTransport.Input.ReadAllAsync();
// Check the provided request
Assert.Equal(2, sentRequests.Count);
Assert.Equal(3, sentRequests.Count);
// Check the messages received
Assert.Equal(message1Payload, message);
@ -366,6 +409,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
var sentRequests = new List<byte[]>();
var tcs = new TaskCompletionSource<HttpResponseMessage>();
var firstPoll = true;
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
@ -380,6 +424,13 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
}
else if (request.Method == HttpMethod.Get)
{
// First poll completes immediately
if (firstPoll)
{
firstPoll = false;
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
// This is the poll task
return await tcs.Task;
@ -426,6 +477,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var sentRequests = new List<byte[]>();
var pollTcs = new TaskCompletionSource<HttpResponseMessage>();
var deleteTcs = new TaskCompletionSource<object>();
var firstPoll = true;
var mockHttpHandler = new Mock<HttpMessageHandler>();
mockHttpHandler.Protected()
@ -440,6 +492,13 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
}
else if (request.Method == HttpMethod.Get)
{
// First poll completes immediately
if (firstPoll)
{
firstPoll = false;
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
cancellationToken.Register(() => pollTcs.TrySetCanceled(cancellationToken));
// This is the poll task
return await pollTcs.Task;
@ -538,7 +597,13 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
await Task.Yield();
if (Interlocked.Increment(ref numPolls) < 3)
if (numPolls == 0)
{
numPolls++;
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
if (numPolls++ < 3)
{
throw new OperationCanceledException();
}

View File

@ -6,6 +6,8 @@
<ItemGroup>
<Compile Include="..\..\src\Common\MemoryBufferWriter.cs" Link="MemoryBufferWriter.cs" />
<Compile Include="..\..\src\Common\TextMessageFormatter.cs" Link="TextMessageFormatter.cs" />
<Compile Include="..\..\src\Common\TextMessageParser.cs" Link="TextMessageParser.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -3,11 +3,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Internal;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.SignalR.Client.Tests
@ -40,6 +40,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public static bool IsLongPollRequest(HttpRequestMessage request)
{
return request.Method == HttpMethod.Get &&
!IsServerSentEventsRequest(request) &&
(request.RequestUri.PathAndQuery.Contains("?id=") || request.RequestUri.PathAndQuery.Contains("&id="));
}
@ -49,6 +50,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
(request.RequestUri.PathAndQuery.Contains("?id=") || request.RequestUri.PathAndQuery.Contains("&id="));
}
public static bool IsServerSentEventsRequest(HttpRequestMessage request)
{
return request.Method == HttpMethod.Get && request.Headers.Accept.Any(h => h.MediaType == "text/event-stream");
}
public static bool IsSocketSendRequest(HttpRequestMessage request)
{
return request.Method == HttpMethod.Post &&

View File

@ -12,7 +12,6 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.SignalR.Protocol;
using Newtonsoft.Json;

View File

@ -7,10 +7,14 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.SignalR.Client.Tests
{
delegate Task<HttpResponseMessage> RequestDelegate(HttpRequestMessage requestMessage, CancellationToken cancellationToken);
public class TestHttpMessageHandler : HttpMessageHandler
{
private List<HttpRequestMessage> _receivedRequests = new List<HttpRequestMessage>();
private Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handler;
private RequestDelegate _app;
private List<Func<RequestDelegate, RequestDelegate>> _middleware = new List<Func<RequestDelegate, RequestDelegate>>();
public IReadOnlyList<HttpRequestMessage> ReceivedRequests
{
@ -23,14 +27,29 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
}
}
public TestHttpMessageHandler(bool autoNegotiate = true)
public TestHttpMessageHandler(bool autoNegotiate = true, bool handleFirstPoll = true)
{
_handler = BaseHandler;
if (autoNegotiate)
{
OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));
}
if (handleFirstPoll)
{
var firstPoll = true;
OnRequest(async (request, next, cancellationToken) =>
{
if (ResponseUtils.IsLongPollRequest(request) && firstPoll)
{
firstPoll = false;
return ResponseUtils.CreateResponse(HttpStatusCode.OK);
}
else
{
return await next();
}
});
}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
@ -40,9 +59,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
lock (_receivedRequests)
{
_receivedRequests.Add(request);
if (_app == null)
{
_middleware.Reverse();
RequestDelegate handler = BaseHandler;
foreach (var middleware in _middleware)
{
handler = middleware(handler);
}
_app = handler;
}
}
return await _handler(request, cancellationToken);
return await _app(request, cancellationToken);
}
public static TestHttpMessageHandler CreateDefault()
@ -80,8 +111,18 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public void OnRequest(Func<HttpRequestMessage, Func<Task<HttpResponseMessage>>, CancellationToken, Task<HttpResponseMessage>> handler)
{
var nextHandler = _handler;
_handler = (request, cancellationToken) => handler(request, () => nextHandler(request, cancellationToken), cancellationToken);
void OnRequestCore(Func<RequestDelegate, RequestDelegate> middleware)
{
_middleware.Add(middleware);
}
OnRequestCore(next =>
{
return (request, cancellationToken) =>
{
return handler(request, () => next(request, cancellationToken), cancellationToken);
};
});
}
public void OnGet(string pathAndQuery, Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handler) => OnRequest(HttpMethod.Get, pathAndQuery, handler);

View File

@ -9,7 +9,6 @@ using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters

View File

@ -5,7 +5,7 @@ using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.Internal;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters

View File

@ -4,7 +4,7 @@
using System;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.Internal;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters

View File

@ -4,7 +4,7 @@
using System;
using System.Buffers;
using System.Text;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.Internal;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters

View File

@ -8,7 +8,6 @@ using System.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

View File

@ -8,7 +8,6 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol

View File

@ -4,6 +4,11 @@
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\Common\BinaryMessageFormatter.cs" Link="BinaryMessageFormatter.cs" />
<Compile Include="..\..\src\Common\BinaryMessageParser.cs" Link="BinaryMessageParser.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\xunit.runner.json" Link="xunit.runner.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@ -13,14 +13,14 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
return message;
}
public Task EchoGroup(string group, string message)
public Task EchoGroup(string groupName, string message)
{
return Clients.Group(group).SendAsync("Echo", message);
return Clients.Group(groupName).SendAsync("Echo", message);
}
public Task AddSelfToGroup(string group)
public Task AddSelfToGroup(string groupName)
{
return Groups.AddAsync(Context.ConnectionId, group);
return Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
}
}

View File

@ -26,16 +26,16 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
var options = provider.GetService<IOptions<RedisOptions>>();
Assert.NotNull(options.Value);
Assert.NotNull(options.Value.Options);
Assert.Equal(password, options.Value.Options.Password);
Assert.Collection(options.Value.Options.EndPoints,
Assert.NotNull(options.Value.Configuration);
Assert.Equal(password, options.Value.Configuration.Password);
Assert.Collection(options.Value.Configuration.EndPoints,
endpoint =>
{
var dnsEndpoint = Assert.IsType<DnsEndPoint>(endpoint);
Assert.Equal(host, dnsEndpoint.Host);
Assert.Equal(port, dnsEndpoint.Port);
});
Assert.Equal(useSsl, options.Value.Options.Ssl);
Assert.Equal(useSsl, options.Value.Configuration.Ssl);
}
}
}

View File

@ -110,7 +110,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager.OnConnectedAsync(connection1).OrTimeout();
await manager.OnConnectedAsync(connection2).OrTimeout();
await manager.AddGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
await manager.AddToGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
await manager.SendGroupAsync("gunit", "Hello", new object[] { "World" }).OrTimeout();
@ -134,11 +134,11 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager.OnConnectedAsync(connection1).OrTimeout();
await manager.OnConnectedAsync(connection2).OrTimeout();
await manager.AddGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
await manager.AddGroupAsync(connection2.ConnectionId, "gunit").OrTimeout();
await manager.AddToGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
await manager.AddToGroupAsync(connection2.ConnectionId, "gunit").OrTimeout();
var excludedIds = new List<string> { client2.Connection.ConnectionId };
await manager.SendGroupExceptAsync("gunit", "Hello", new object[] { "World" }, excludedIds).OrTimeout();
var excludedConnectionIds = new List<string> { client2.Connection.ConnectionId };
await manager.SendGroupExceptAsync("gunit", "Hello", new object[] { "World" }, excludedConnectionIds).OrTimeout();
await AssertMessageAsync(client1);
Assert.Null(client2.TryRead());
@ -257,7 +257,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager1.OnConnectedAsync(connection).OrTimeout();
await manager1.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
@ -278,7 +278,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager.OnConnectedAsync(connection).OrTimeout();
await manager.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.OnDisconnectedAsync(connection).OrTimeout();
@ -301,7 +301,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager.OnConnectedAsync(connection).OrTimeout();
await manager.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
}
}
@ -319,7 +319,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager1.OnConnectedAsync(connection).OrTimeout();
await manager2.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
}
}
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager1.OnConnectedAsync(connection).OrTimeout();
await manager2.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
@ -358,8 +358,8 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager.OnConnectedAsync(connection).OrTimeout();
await manager.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
@ -382,8 +382,8 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager1.OnConnectedAsync(connection).OrTimeout();
await manager1.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
@ -406,13 +406,13 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
await manager1.OnConnectedAsync(connection).OrTimeout();
await manager1.AddGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
await AssertMessageAsync(client);
await manager2.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
@ -484,9 +484,9 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
await manager.OnConnectedAsync(connection1).OrTimeout();
await manager.AddGroupAsync(connection1.ConnectionId, "group");
await manager.AddToGroupAsync(connection1.ConnectionId, "group");
await manager.OnConnectedAsync(connection2).OrTimeout();
await manager.AddGroupAsync(connection2.ConnectionId, "group");
await manager.AddToGroupAsync(connection2.ConnectionId, "group");
await manager.SendGroupAsync("group", "Hello", new object[] { "World" }).OrTimeout();
// connection1 will throw when receiving a group message, we are making sure other connections
@ -550,7 +550,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
private RedisHubLifetimeManager<MyHub> CreateLifetimeManager(TestRedisServer server, MessagePackHubProtocolOptions messagePackOptions = null, JsonHubProtocolOptions jsonOptions = null)
{
var options = new RedisOptions() { Factory = async (t) => await Task.FromResult(new TestConnectionMultiplexer(server)) };
var options = new RedisOptions() { ConnectionFactory = async (t) => await Task.FromResult(new TestConnectionMultiplexer(server)) };
messagePackOptions = messagePackOptions ?? new MessagePackHubProtocolOptions();
jsonOptions = jsonOptions ?? new JsonHubProtocolOptions();

View File

@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
var decoded = protocol.ReadInvocation(testData.Encoded);
Assert.Equal(testData.Decoded.ExcludedIds, decoded.ExcludedIds);
Assert.Equal(testData.Decoded.ExcludedConnectionIds, decoded.ExcludedConnectionIds);
// Verify the deserialized object has the necessary serialized forms
foreach (var hubProtocol in hubProtocols)
@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
// Actual invocation doesn't matter because we're using a dummy hub protocol.
// But the dummy protocol will check that we gave it the test message to make sure everything flows through properly.
var encoded = protocol.WriteInvocation(_testMessage.Target, _testMessage.Arguments, testData.Decoded.ExcludedIds);
var encoded = protocol.WriteInvocation(_testMessage.Target, _testMessage.Arguments, testData.Decoded.ExcludedConnectionIds);
Assert.Equal(testData.Encoded, encoded);
}

Some files were not shown because too many files have changed in this diff Show More