Merge
This commit is contained in:
commit
8985fee4b5
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,6 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
|||
|
||||
public class TestConnectionInherentKeepAliveFeature : IConnectionInherentKeepAliveFeature
|
||||
{
|
||||
public TimeSpan KeepAliveInterval { get; } = TimeSpan.Zero;
|
||||
public bool HasInherentKeepAlive { get; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@aspnet/signalr",
|
||||
"version": "1.0.0-preview3-t000",
|
||||
"version": "1.1.0-preview1-t000",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
version:2.1.0-preview3-17002
|
||||
commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f
|
||||
version:2.1.0-preview3-17018
|
||||
commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Client
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
||||
{
|
||||
internal static class Utils
|
||||
{
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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>
|
||||
{
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Internal
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
{
|
||||
public readonly struct SerializedMessage
|
||||
{
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.SignalR.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) =>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 &&
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue