diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/BroadcastBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/BroadcastBenchmark.cs index 9b09dd8017..8028bbb06c 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/BroadcastBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/BroadcastBenchmark.cs @@ -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); } diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubActivatorBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubActivatorBenchmark.cs index d8e38f9ade..a18034c71e 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubActivatorBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubActivatorBenchmark.cs @@ -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 diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubLifetimeManagerBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubLifetimeManagerBenchmark.cs index 43c164902a..d2d0a438be 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubLifetimeManagerBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubLifetimeManagerBenchmark.cs @@ -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()); } } -} \ No newline at end of file +} diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/HubConnectionStartBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/HubConnectionStartBenchmark.cs index d39a4c2601..fbf8da9afb 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/HubConnectionStartBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/HubConnectionStartBenchmark.cs @@ -76,6 +76,6 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks public class TestConnectionInherentKeepAliveFeature : IConnectionInherentKeepAliveFeature { - public TimeSpan KeepAliveInterval { get; } = TimeSpan.Zero; + public bool HasInherentKeepAlive { get; } = true; } } diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs index 575ad44f82..f08d29a6e6 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs @@ -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 { diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj index 63357c6ff1..545d54f9b3 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj @@ -5,6 +5,11 @@ netcoreapp2.1 + + + + + diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/NegotiateProtocolBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/NegotiateProtocolBenchmark.cs index 6718581ab9..2e4120e187 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/NegotiateProtocolBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/NegotiateProtocolBenchmark.cs @@ -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 diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisHubLifetimeManagerBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisHubLifetimeManagerBenchmark.cs index 38d0e18782..3e333ddd74 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisHubLifetimeManagerBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisHubLifetimeManagerBenchmark.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks private RedisHubLifetimeManager _manager2; private TestClient[] _clients; private object[] _args; - private readonly List _excludedIds = new List(); + private readonly List _excludedConnectionIds = new List(); private readonly List _sendIds = new List(); private readonly List _groups = new List(); private readonly List _users = new List(); @@ -42,18 +42,18 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks var protocols = GenerateProtocols(ProtocolCount).ToArray(); var options = Options.Create(new RedisOptions() { - Factory = _ => Task.FromResult(new TestConnectionMultiplexer(server)) + ConnectionFactory = _ => Task.FromResult(new TestConnectionMultiplexer(server)) }); var resolver = new DefaultHubProtocolResolver(protocols, NullLogger.Instance); _manager1 = new RedisHubLifetimeManager(logger, options, resolver); _manager2 = new RedisHubLifetimeManager(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] diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisProtocolBenchmark.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisProtocolBenchmark.cs index 9bc29aa380..3008ed999c 100644 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisProtocolBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisProtocolBenchmark.cs @@ -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 _excludedIdsSmall; - private IReadOnlyList _excludedIdsLarge; + private IReadOnlyList _excludedConnectionIdsSmall; + private IReadOnlyList _excludedConnectionIdsLarge; private byte[] _writtenAck; private byte[] _writtenGroupCommand; private byte[] _writtenInvocationNoExclusions; @@ -36,14 +39,14 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks _args = Array.Empty(); _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] diff --git a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Shared/TestConnectionInherentKeepAliveFeature.cs b/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Shared/TestConnectionInherentKeepAliveFeature.cs deleted file mode 100644 index d91b3f8580..0000000000 --- a/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/Shared/TestConnectionInherentKeepAliveFeature.cs +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/build/dependencies.props b/build/dependencies.props index 35108cd17a..de6e769e20 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,76 +1,76 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 0.10.13 3.1.0 - 2.1.0-preview3-17002 + 2.1.0-preview3-17018 1.7.3.4 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 0.5.0-preview2-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 4.5.0-preview2-26406-04 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 - 2.1.0-preview3-32196 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-a-preview3-inherent-keep-alive-bool-17670 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 0.5.0-preview2-32233 + 2.1.0-a-preview3-inherent-keep-alive-bool-17670 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 4.5.0-preview3-26413-02 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 2.0.0 - 2.1.0-preview2-26406-04 + 2.1.0-preview3-26413-05 15.6.1 4.7.49 11.0.2 1.2.4 - 4.5.0-preview2-26406-04 - 4.5.0-preview2-26406-04 - 4.5.0-preview2-26406-04 - 4.5.0-preview2-26406-04 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 3.1.1 4.3.0 - 4.5.0-preview2-26406-04 - 4.5.0-preview2-26406-04 - 4.5.0-preview2-26406-04 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/clients/ts/signalr-protocol-msgpack/package-lock.json b/clients/ts/signalr-protocol-msgpack/package-lock.json index 28f546b661..064dcdcba1 100644 --- a/clients/ts/signalr-protocol-msgpack/package-lock.json +++ b/clients/ts/signalr-protocol-msgpack/package-lock.json @@ -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": { diff --git a/clients/ts/signalr-protocol-msgpack/package.json b/clients/ts/signalr-protocol-msgpack/package.json index 0dd9d8f47d..a232fc89f8 100644 --- a/clients/ts/signalr-protocol-msgpack/package.json +++ b/clients/ts/signalr-protocol-msgpack/package.json @@ -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", diff --git a/clients/ts/signalr/package-lock.json b/clients/ts/signalr/package-lock.json index 0447edc39b..bded6a88f4 100644 --- a/clients/ts/signalr/package-lock.json +++ b/clients/ts/signalr/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aspnet/signalr", - "version": "1.0.0-preview3-t000", + "version": "1.1.0-preview1-t000", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/clients/ts/signalr/package.json b/clients/ts/signalr/package.json index 4674918d1a..c70d4dde4c 100644 --- a/clients/ts/signalr/package.json +++ b/clients/ts/signalr/package.json @@ -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", diff --git a/clients/ts/signalr/spec/HttpConnection.spec.ts b/clients/ts/signalr/spec/HttpConnection.spec.ts index 15184bd686..09bd65c4f7 100644 --- a/clients/ts/signalr/spec/HttpConnection.spec.ts +++ b/clients/ts/signalr/spec/HttpConnection.spec.ts @@ -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); diff --git a/clients/ts/signalr/src/LongPollingTransport.ts b/clients/ts/signalr/src/LongPollingTransport.ts index 5f3e453277..86d3e8376f 100644 --- a/clients/ts/signalr/src/LongPollingTransport.ts +++ b/clients/ts/signalr/src/LongPollingTransport.ts @@ -31,7 +31,7 @@ export class LongPollingTransport implements ITransport { this.logMessageContent = logMessageContent; } - public connect(url: string, transferFormat: TransferFormat): Promise { + public async connect(url: string, transferFormat: TransferFormat): Promise { 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 { - 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 { 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."); diff --git a/korebuild-lock.txt b/korebuild-lock.txt index c879a84a90..ce2f277c53 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17002 -commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f +version:2.1.0-preview3-17018 +commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be diff --git a/samples/ChatSample/PresenceHubLifetimeManager.cs b/samples/ChatSample/PresenceHubLifetimeManager.cs index 87d8bc3a27..4ab7abffb8 100644 --- a/samples/ChatSample/PresenceHubLifetimeManager.cs +++ b/samples/ChatSample/PresenceHubLifetimeManager.cs @@ -143,9 +143,9 @@ namespace ChatSample return _wrappedHubLifetimeManager.SendAllAsync(methodName, args); } - public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList excludedIds) + public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList 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 excludedIds) + public override Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList excludedConnectionIds) { - return _wrappedHubLifetimeManager.SendGroupExceptAsync(groupName, methodName, args, excludedIds); + return _wrappedHubLifetimeManager.SendGroupExceptAsync(groupName, methodName, args, excludedConnectionIds); } public override Task SendUsersAsync(IReadOnlyList userIds, string methodName, object[] args) diff --git a/samples/ChatSample/RedisUserTracker.cs b/samples/ChatSample/RedisUserTracker.cs index 40c811d109..644414a6bf 100644 --- a/samples/ChatSample/RedisUserTracker.cs +++ b/samples/ChatSample/RedisUserTracker.cs @@ -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 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(); diff --git a/samples/ClientSample/Tcp/TcpConnection.cs b/samples/ClientSample/Tcp/TcpConnection.cs index c59e73a0ad..1fbb213b9b 100644 --- a/samples/ClientSample/Tcp/TcpConnection.cs +++ b/samples/ClientSample/Tcp/TcpConnection.cs @@ -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 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() { diff --git a/samples/SignalRSamples/Hubs/Chat.cs b/samples/SignalRSamples/Hubs/Chat.cs index 373bfad78b..cabbd4a391 100644 --- a/samples/SignalRSamples/Hubs/Chat.cs +++ b/samples/SignalRSamples/Hubs/Chat.cs @@ -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) diff --git a/samples/SignalRSamples/Hubs/DynamicChat.cs b/samples/SignalRSamples/Hubs/DynamicChat.cs index c6d7a105d9..30d7154351 100644 --- a/samples/SignalRSamples/Hubs/DynamicChat.cs +++ b/samples/SignalRSamples/Hubs/DynamicChat.cs @@ -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) diff --git a/samples/SignalRSamples/Hubs/HubTChat.cs b/samples/SignalRSamples/Hubs/HubTChat.cs index 79bd59a2e3..3acb04f323 100644 --- a/samples/SignalRSamples/Hubs/HubTChat.cs +++ b/samples/SignalRSamples/Hubs/HubTChat.cs @@ -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) diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs b/src/Common/BinaryMessageFormatter.cs similarity index 93% rename from src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs rename to src/Common/BinaryMessageFormatter.cs index 0ef7d0b5fe..62e31a8459 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs +++ b/src/Common/BinaryMessageFormatter.cs @@ -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 output) { diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs b/src/Common/BinaryMessageParser.cs similarity index 96% rename from src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs rename to src/Common/BinaryMessageParser.cs index 9c5ca212eb..0f76cc8c72 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs +++ b/src/Common/BinaryMessageParser.cs @@ -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; diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs b/src/Common/TextMessageFormatter.cs similarity index 86% rename from src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs rename to src/Common/TextMessageFormatter.cs index 058172984e..32470f320b 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs +++ b/src/Common/TextMessageFormatter.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs b/src/Common/TextMessageParser.cs similarity index 88% rename from src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs rename to src/Common/TextMessageParser.cs index 566465e278..3d7d233e59 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs +++ b/src/Common/TextMessageParser.cs @@ -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 buffer, out ReadOnlySequence payload) { diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnection.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnection.cs index dce91f0aab..f2e827979a 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnection.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnection.cs @@ -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 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(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(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; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnectionOptions.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnectionOptions.cs index 79cdd0ac4f..9bf7db2fb6 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnectionOptions.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnectionOptions.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/DefaultTransportFactory.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/DefaultTransportFactory.cs index e781681b47..6332d276f5 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/DefaultTransportFactory.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/DefaultTransportFactory.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/LongPollingTransport.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/LongPollingTransport.cs index 4059049a96..860f54b3ee 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/LongPollingTransport.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/LongPollingTransport.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal _logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger(); } - 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 diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/SendUtils.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/SendUtils.cs similarity index 99% rename from src/Microsoft.AspNetCore.Http.Connections.Client/SendUtils.cs rename to src/Microsoft.AspNetCore.Http.Connections.Client/Internal/SendUtils.cs index 6439355745..d3cff78214 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/SendUtils.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/SendUtils.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/ServerSentEventsTransport.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/ServerSentEventsTransport.cs index 59ca9d7cbf..b92931a4d0 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/ServerSentEventsTransport.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/ServerSentEventsTransport.cs @@ -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(); diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/Utils.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/Utils.cs similarity index 94% rename from src/Microsoft.AspNetCore.Http.Connections.Client/Utils.cs rename to src/Microsoft.AspNetCore.Http.Connections.Client/Internal/Utils.cs index 385ccf145e..f92f89a3a0 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/Utils.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/Utils.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Http.Connections.Client +namespace Microsoft.AspNetCore.Http.Connections.Client.Internal { internal static class Utils { diff --git a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/WebSocketsTransport.cs b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/WebSocketsTransport.cs index 4520162c72..c6ebeabce3 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/WebSocketsTransport.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Client/Internal/WebSocketsTransport.cs @@ -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(); diff --git a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/AvailableTransport.cs b/src/Microsoft.AspNetCore.Http.Connections.Common/AvailableTransport.cs similarity index 72% rename from src/Microsoft.AspNetCore.Http.Connections.Common/Internal/AvailableTransport.cs rename to src/Microsoft.AspNetCore.Http.Connections.Common/AvailableTransport.cs index 62e68b0ca3..92d5fe16b4 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/AvailableTransport.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Common/AvailableTransport.cs @@ -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 TransferFormats { get; set; } + public IList TransferFormats { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Http.Connections.Common/ConnectionInherentKeepAliveFeature.cs b/src/Microsoft.AspNetCore.Http.Connections.Common/ConnectionInherentKeepAliveFeature.cs deleted file mode 100644 index 72f6d547c6..0000000000 --- a/src/Microsoft.AspNetCore.Http.Connections.Common/ConnectionInherentKeepAliveFeature.cs +++ /dev/null @@ -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; - } - } -} diff --git a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/HttpTransports.cs b/src/Microsoft.AspNetCore.Http.Connections.Common/HttpTransports.cs similarity index 91% rename from src/Microsoft.AspNetCore.Http.Connections.Common/Internal/HttpTransports.cs rename to src/Microsoft.AspNetCore.Http.Connections.Common/HttpTransports.cs index 193defd7ef..5743ea324d 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/HttpTransports.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Common/HttpTransports.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/NegotiateProtocol.cs b/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs similarity index 99% rename from src/Microsoft.AspNetCore.Http.Connections.Common/Internal/NegotiateProtocol.cs rename to src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs index 5822113ca5..f1cd03ac62 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/NegotiateProtocol.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/NegotiationResponse.cs b/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiationResponse.cs similarity index 69% rename from src/Microsoft.AspNetCore.Http.Connections.Common/Internal/NegotiationResponse.cs rename to src/Microsoft.AspNetCore.Http.Connections.Common/NegotiationResponse.cs index 528ea3cca0..70a930c1a2 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Common/Internal/NegotiationResponse.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiationResponse.cs @@ -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 AvailableTransports { get; set; } + public IList AvailableTransports { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionContext.cs b/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionContext.cs index 1e2b330860..d496d1d29d 100644 --- a/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionContext.cs +++ b/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionContext.cs @@ -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(this); Features.Set(this); Features.Set(this); + Features.Set(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 Items { get diff --git a/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionDispatcher.cs b/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionDispatcher.cs index 6695cb853c..0f4f88551f 100644 --- a/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionDispatcher.cs +++ b/src/Microsoft.AspNetCore.Http.Connections/Internal/HttpConnectionDispatcher.cs @@ -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() != 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(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 diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs index 1752f58283..44d6bdb969 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs @@ -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() == null) + + // We use '!== true' because it could be null, which we treat as false. + if (connectionState.Connection.Features.Get()?.HasInherentKeepAlive != true) { Log.StartingServerTimeoutTimer(_logger, ServerTimeout); timeoutTimer = new Timer( diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/InvocationRequest.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/Internal/InvocationRequest.cs similarity index 99% rename from src/Microsoft.AspNetCore.SignalR.Client.Core/InvocationRequest.cs rename to src/Microsoft.AspNetCore.SignalR.Client.Core/Internal/InvocationRequest.cs index d8b2f56fa4..dc3c433663 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client.Core/InvocationRequest.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/Internal/InvocationRequest.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubException.cs b/src/Microsoft.AspNetCore.SignalR.Common/HubException.cs similarity index 72% rename from src/Microsoft.AspNetCore.SignalR.Client.Core/HubException.cs rename to src/Microsoft.AspNetCore.SignalR.Common/HubException.cs index b2a9667ea2..62759e05a5 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubException.cs +++ b/src/Microsoft.AspNetCore.SignalR.Common/HubException.cs @@ -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) + { + } } } diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj b/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj index 7656d3074b..98d1cf30f7 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj +++ b/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj @@ -10,6 +10,8 @@ + + diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HandshakeProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HandshakeProtocol.cs index 0cd599c672..9e80ca0446 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HandshakeProtocol.cs +++ b/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HandshakeProtocol.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Core/ClientProxyExtensions.cs similarity index 99% rename from src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs rename to src/Microsoft.AspNetCore.SignalR.Core/ClientProxyExtensions.cs index 4fd087890c..18c1deda51 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/IClientProxyExtensions.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/ClientProxyExtensions.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNetCore.SignalR { - public static class IClientProxyExtensions + public static class ClientProxyExtensions { /// /// Invokes a method on the connection(s) represented by the instance. diff --git a/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubLifetimeManager.cs b/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubLifetimeManager.cs index 299f9aef43..4a5da0f4e0 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubLifetimeManager.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubLifetimeManager.cs @@ -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 excludedIds) + public override Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList excludedConnectionIds) { if (groupName == null) { @@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.SignalR List 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 excludedIds) + public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList excludedConnectionIds) { - return SendToAllConnections(methodName, args, connection => !excludedIds.Contains(connection.ConnectionId)); + return SendToAllConnections(methodName, args, connection => !excludedConnectionIds.Contains(connection.ConnectionId)); } public override Task SendConnectionsAsync(IReadOnlyList connectionIds, string methodName, object[] args) diff --git a/src/Microsoft.AspNetCore.SignalR.Core/DynamicHubClients.cs b/src/Microsoft.AspNetCore.SignalR.Core/DynamicHubClients.cs index 47ffdeae00..2f49cc9d2d 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/DynamicHubClients.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/DynamicHubClients.cs @@ -16,13 +16,13 @@ namespace Microsoft.AspNetCore.SignalR } public dynamic All => new DynamicClientProxy(_clients.All); - public dynamic AllExcept(IReadOnlyList excludedIds) => new DynamicClientProxy(_clients.AllExcept(excludedIds)); + public dynamic AllExcept(IReadOnlyList 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 connectionIds) => new DynamicClientProxy(_clients.Clients(connectionIds)); public dynamic Group(string groupName) => new DynamicClientProxy(_clients.Group(groupName)); public dynamic Groups(IReadOnlyList groupNames) => new DynamicClientProxy(_clients.Groups(groupNames)); - public dynamic GroupExcept(string groupName, IReadOnlyList excludedIds) => new DynamicClientProxy(_clients.GroupExcept(groupName, excludedIds)); + public dynamic GroupExcept(string groupName, IReadOnlyList 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)); diff --git a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs index 3e909ce3d0..c0787f4f03 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs @@ -52,7 +52,8 @@ namespace Microsoft.AspNetCore.SignalR public virtual IDictionary 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() == null) + // != true needed because it could be null (which we treat as false) + if (Features.Get()?.HasInherentKeepAlive != true) { // Only register KeepAlive after protocol handshake otherwise KeepAliveTick could try to write without having a ProtocolReaderWriter Features.Get()?.OnHeartbeat(state => ((HubConnectionContext)state).KeepAliveTick(), this); diff --git a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs index 170461656a..9c7ff24e4f 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs @@ -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); } } } diff --git a/src/Microsoft.AspNetCore.SignalR.Core/HubLifetimeManager.cs b/src/Microsoft.AspNetCore.SignalR.Core/HubLifetimeManager.cs index e22080d346..588ec88230 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/HubLifetimeManager.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/HubLifetimeManager.cs @@ -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 excludedIds); + public abstract Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList excludedConnectionIds); public abstract Task SendConnectionAsync(string connectionId, string methodName, object[] args); @@ -24,15 +24,15 @@ namespace Microsoft.AspNetCore.SignalR public abstract Task SendGroupsAsync(IReadOnlyList groupNames, string methodName, object[] args); - public abstract Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList excludedIds); + public abstract Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList excludedConnectionIds); public abstract Task SendUserAsync(string userId, string methodName, object[] args); public abstract Task SendUsersAsync(IReadOnlyList 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); } } diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Hub`T.cs b/src/Microsoft.AspNetCore.SignalR.Core/Hub`T.cs index 3424e77c53..8bce9b3507 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Hub`T.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Hub`T.cs @@ -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 : Hub where T : class diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IGroupManager.cs b/src/Microsoft.AspNetCore.SignalR.Core/IGroupManager.cs index 71b22289fd..b96f4f10df 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/IGroupManager.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/IGroupManager.cs @@ -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); } } diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IHubClientsExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Core/IHubClientsExtensions.cs new file mode 100644 index 0000000000..0d19846948 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Core/IHubClientsExtensions.cs @@ -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 + { + /// + /// + /// + /// The first connection to exclude. + /// + public static T AllExcept(this IHubClients hubClients, string excludedConnectionId1) + { + return hubClients.AllExcept(new [] { excludedConnectionId1 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// + public static T AllExcept(this IHubClients hubClients, string excludedConnectionId1, string excludedConnectionId2) + { + return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// + public static T AllExcept(this IHubClients hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3) + { + return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// + public static T AllExcept(this IHubClients hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4) + { + return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// + public static T AllExcept(this IHubClients hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5) + { + return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// The sixth connection to exclude. + /// + public static T AllExcept(this IHubClients hubClients, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5, string excludedConnectionId6) + { + return hubClients.AllExcept(new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5, excludedConnectionId6 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// The sixth connection to exclude. + /// The seventh connection to exclude. + /// + public static T AllExcept(this IHubClients 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 }); + } + + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// The sixth connection to exclude. + /// The seventh connection to exclude. + /// The eighth connection to exclude. + /// + public static T AllExcept(this IHubClients 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 }); + } + + /// + /// + /// + /// The first connection to include. + /// + public static T Clients(this IHubClients hubClients, string connection1) + { + return hubClients.Clients(new [] { connection1 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// + public static T Clients(this IHubClients hubClients, string connection1, string connection2) + { + return hubClients.Clients(new [] { connection1, connection2 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// The third connection to include. + /// + public static T Clients(this IHubClients hubClients, string connection1, string connection2, string connection3) + { + return hubClients.Clients(new [] { connection1, connection2, connection3 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// The third connection to include. + /// The fourth connection to include. + /// + public static T Clients(this IHubClients hubClients, string connection1, string connection2, string connection3, string connection4) + { + return hubClients.Clients(new [] { connection1, connection2, connection3, connection4 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// The third connection to include. + /// The fourth connection to include. + /// The fifth connection to include. + /// + public static T Clients(this IHubClients hubClients, string connection1, string connection2, string connection3, string connection4, string connection5) + { + return hubClients.Clients(new [] { connection1, connection2, connection3, connection4, connection5 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// The third connection to include. + /// The fourth connection to include. + /// The fifth connection to include. + /// The sixth connection to include. + /// + public static T Clients(this IHubClients hubClients, string connection1, string connection2, string connection3, string connection4, string connection5, string connection6) + { + return hubClients.Clients(new [] { connection1, connection2, connection3, connection4, connection5, connection6 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// The third connection to include. + /// The fourth connection to include. + /// The fifth connection to include. + /// The sixth connection to include. + /// The seventh connection to include. + /// + public static T Clients(this IHubClients 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 }); + } + + /// + /// + /// + /// The first connection to include. + /// The second connection to include. + /// The third connection to include. + /// The fourth connection to include. + /// The fifth connection to include. + /// The sixth connection to include. + /// The seventh connection to include. + /// The eighth connection to include. + /// + public static T Clients(this IHubClients 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 }); + } + + /// + /// + /// + /// The first group to include. + /// + public static T Groups(this IHubClients hubClients, string group1) + { + return hubClients.Groups(new [] { group1 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// + public static T Groups(this IHubClients hubClients, string group1, string group2) + { + return hubClients.Groups(new [] { group1, group2 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// The third group to include. + /// + public static T Groups(this IHubClients hubClients, string group1, string group2, string group3) + { + return hubClients.Groups(new [] { group1, group2, group3 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// The third group to include. + /// The fourth group to include. + /// + public static T Groups(this IHubClients hubClients, string group1, string group2, string group3, string group4) + { + return hubClients.Groups(new [] { group1, group2, group3, group4 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// The third group to include. + /// The fourth group to include. + /// The fifth group to include. + /// + public static T Groups(this IHubClients hubClients, string group1, string group2, string group3, string group4, string group5) + { + return hubClients.Groups(new [] { group1, group2, group3, group4, group5 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// The third group to include. + /// The fourth group to include. + /// The fifth group to include. + /// The sixth group to include. + /// + public static T Groups(this IHubClients hubClients, string group1, string group2, string group3, string group4, string group5, string group6) + { + return hubClients.Groups(new [] { group1, group2, group3, group4, group5, group6 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// The third group to include. + /// The fourth group to include. + /// The fifth group to include. + /// The sixth group to include. + /// The seventh group to include. + /// + public static T Groups(this IHubClients 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 }); + } + + /// + /// + /// + /// The first group to include. + /// The second group to include. + /// The third group to include. + /// The fourth group to include. + /// The fifth group to include. + /// The sixth group to include. + /// The seventh group to include. + /// The eighth group to include. + /// + public static T Groups(this IHubClients 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 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// + public static T GroupExcept(this IHubClients hubClients, string groupName, string excludedConnectionId1) + { + return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// + public static T GroupExcept(this IHubClients hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2) + { + return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// + public static T GroupExcept(this IHubClients hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3) + { + return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// + public static T GroupExcept(this IHubClients hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4) + { + return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// + public static T GroupExcept(this IHubClients hubClients, string groupName, string excludedConnectionId1, string excludedConnectionId2, string excludedConnectionId3, string excludedConnectionId4, string excludedConnectionId5) + { + return hubClients.GroupExcept(groupName, new [] { excludedConnectionId1, excludedConnectionId2, excludedConnectionId3, excludedConnectionId4, excludedConnectionId5 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// The sixth connection to exclude. + /// + public static T GroupExcept(this IHubClients 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 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// The sixth connection to exclude. + /// The seventh connection to exclude. + /// + public static T GroupExcept(this IHubClients 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 }); + } + + /// + /// + /// + /// + /// The first connection to exclude. + /// The second connection to exclude. + /// The third connection to exclude. + /// The fourth connection to exclude. + /// The fifth connection to exclude. + /// The sixth connection to exclude. + /// The seventh connection to exclude. + /// The eighth connection to exclude. + /// + public static T GroupExcept(this IHubClients 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 }); + } + + /// + /// + /// + /// The first user to include. + /// + public static T Users(this IHubClients hubClients, string user1) + { + return hubClients.Users(new [] { user1 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// + public static T Users(this IHubClients hubClients, string user1, string user2) + { + return hubClients.Users(new [] { user1, user2 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// The third user to include. + /// + public static T Users(this IHubClients hubClients, string user1, string user2, string user3) + { + return hubClients.Users(new [] { user1, user2, user3 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// The third user to include. + /// The fourth user to include. + /// + public static T Users(this IHubClients hubClients, string user1, string user2, string user3, string user4) + { + return hubClients.Users(new [] { user1, user2, user3, user4 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// The third user to include. + /// The fourth user to include. + /// The fifth user to include. + /// + public static T Users(this IHubClients hubClients, string user1, string user2, string user3, string user4, string user5) + { + return hubClients.Users(new [] { user1, user2, user3, user4, user5 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// The third user to include. + /// The fourth user to include. + /// The fifth user to include. + /// The sixth user to include. + /// + public static T Users(this IHubClients hubClients, string user1, string user2, string user3, string user4, string user5, string user6) + { + return hubClients.Users(new [] { user1, user2, user3, user4, user5, user6 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// The third user to include. + /// The fourth user to include. + /// The fifth user to include. + /// The sixth user to include. + /// The seventh user to include. + /// + public static T Users(this IHubClients 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 }); + } + + /// + /// + /// + /// The first user to include. + /// The second user to include. + /// The third user to include. + /// The fourth user to include. + /// The fifth user to include. + /// The sixth user to include. + /// The seventh user to include. + /// The eighth user to include. + /// + public static T Users(this IHubClients 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 }); + } + } +} diff --git a/src/Microsoft.AspNetCore.SignalR.Core/IHubClients`T.cs b/src/Microsoft.AspNetCore.SignalR.Core/IHubClients`T.cs index 3b4c4ded9a..76e9bb12f1 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/IHubClients`T.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/IHubClients`T.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.SignalR { T All { get; } - T AllExcept(IReadOnlyList excludedIds); + T AllExcept(IReadOnlyList excludedConnectionIds); T Client(string connectionId); @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.SignalR T Groups(IReadOnlyList groupNames); - T GroupExcept(string groupName, IReadOnlyList excludeIds); + T GroupExcept(string groupName, IReadOnlyList excludedConnectionIds); T User(string userId); diff --git a/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubActivator.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubActivator.cs similarity index 92% rename from src/Microsoft.AspNetCore.SignalR.Core/DefaultHubActivator.cs rename to src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubActivator.cs index 7fd3ff10d6..3bb8278b1d 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubActivator.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubActivator.cs @@ -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 : IHubActivator 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) { diff --git a/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubCallerContext.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubCallerContext.cs similarity index 96% rename from src/Microsoft.AspNetCore.SignalR.Core/DefaultHubCallerContext.cs rename to src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubCallerContext.cs index 9a22ef1bd6..ead0dc6f9e 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/DefaultHubCallerContext.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubCallerContext.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubCallerClients.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubCallerClients.cs index b24d60af48..d2694b17b3 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubCallerClients.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubCallerClients.cs @@ -24,9 +24,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal public IClientProxy All => _hubClients.All; - public IClientProxy AllExcept(IReadOnlyList excludedIds) + public IClientProxy AllExcept(IReadOnlyList 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 excludeIds) + public IClientProxy GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) { - return _hubClients.GroupExcept(groupName, excludeIds); + return _hubClients.GroupExcept(groupName, excludedConnectionIds); } public IClientProxy User(string userId) diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients.cs index a5e9531983..d5e9589652 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients.cs @@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal public IClientProxy All { get; } - public IClientProxy AllExcept(IReadOnlyList excludedIds) + public IClientProxy AllExcept(IReadOnlyList excludedConnectionIds) { - return new AllClientsExceptProxy(_lifetimeManager, excludedIds); + return new AllClientsExceptProxy(_lifetimeManager, excludedConnectionIds); } public IClientProxy Client(string connectionId) @@ -32,9 +32,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal return new GroupProxy(_lifetimeManager, groupName); } - public IClientProxy GroupExcept(string groupName, IReadOnlyList excludeIds) + public IClientProxy GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) { - return new GroupExceptProxy(_lifetimeManager, groupName, excludeIds); + return new GroupExceptProxy(_lifetimeManager, groupName, excludedConnectionIds); } public IClientProxy Clients(IReadOnlyList connectionIds) diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients`T.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients`T.cs index c232e15d32..69926e9695 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients`T.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/HubClients`T.cs @@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal public T All { get; } - public T AllExcept(IReadOnlyList excludedIds) + public T AllExcept(IReadOnlyList excludedConnectionIds) { - return TypedClientBuilder.Build(new AllClientsExceptProxy(_lifetimeManager, excludedIds)); + return TypedClientBuilder.Build(new AllClientsExceptProxy(_lifetimeManager, excludedConnectionIds)); } public virtual T Client(string connectionId) @@ -37,9 +37,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal return TypedClientBuilder.Build(new GroupProxy(_lifetimeManager, groupName)); } - public T GroupExcept(string groupName, IReadOnlyList excludeIds) + public T GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) { - return TypedClientBuilder.Build(new GroupExceptProxy(_lifetimeManager, groupName, excludeIds)); + return TypedClientBuilder.Build(new GroupExceptProxy(_lifetimeManager, groupName, excludedConnectionIds)); } public T Groups(IReadOnlyList groupNames) diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/Proxies.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/Proxies.cs index e85633fa28..ccec126b3c 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/Proxies.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/Proxies.cs @@ -78,18 +78,18 @@ namespace Microsoft.AspNetCore.SignalR.Internal { private readonly string _groupName; private readonly HubLifetimeManager _lifetimeManager; - private readonly IReadOnlyList _excludedIds; + private readonly IReadOnlyList _excludedConnectionIds; - public GroupExceptProxy(HubLifetimeManager lifetimeManager, string groupName, IReadOnlyList excludedIds) + public GroupExceptProxy(HubLifetimeManager lifetimeManager, string groupName, IReadOnlyList 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 : IClientProxy where THub : Hub { private readonly HubLifetimeManager _lifetimeManager; - private readonly IReadOnlyList _excludedIds; + private readonly IReadOnlyList _excludedConnectionIds; - public AllClientsExceptProxy(HubLifetimeManager lifetimeManager, IReadOnlyList excludedIds) + public AllClientsExceptProxy(HubLifetimeManager lifetimeManager, IReadOnlyList 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); } } } diff --git a/src/Microsoft.AspNetCore.SignalR.Core/SignalRMarkerService.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/SignalRMarkerService.cs similarity index 81% rename from src/Microsoft.AspNetCore.SignalR.Core/SignalRMarkerService.cs rename to src/Microsoft.AspNetCore.SignalR.Core/Internal/SignalRMarkerService.cs index 592296f03f..06720fe924 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/SignalRMarkerService.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/SignalRMarkerService.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.SignalR.Core/TypedClientBuilder.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/TypedClientBuilder.cs similarity index 99% rename from src/Microsoft.AspNetCore.SignalR.Core/TypedClientBuilder.cs rename to src/Microsoft.AspNetCore.SignalR.Core/Internal/TypedClientBuilder.cs index 7cc4352d4d..bcae8fec8c 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/TypedClientBuilder.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/TypedClientBuilder.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.SignalR.Core/TypedHubClients.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/TypedHubClients.cs similarity index 87% rename from src/Microsoft.AspNetCore.SignalR.Core/TypedHubClients.cs rename to src/Microsoft.AspNetCore.SignalR.Core/Internal/TypedHubClients.cs index d984dbd99e..2906dc7f43 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/TypedHubClients.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/TypedHubClients.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace Microsoft.AspNetCore.SignalR +namespace Microsoft.AspNetCore.SignalR.Internal { internal class TypedHubClients : IHubCallerClients { @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.SignalR public T Others => TypedClientBuilder.Build(_hubClients.Others); - public T AllExcept(IReadOnlyList excludedIds) => TypedClientBuilder.Build(_hubClients.AllExcept(excludedIds)); + public T AllExcept(IReadOnlyList excludedConnectionIds) => TypedClientBuilder.Build(_hubClients.AllExcept(excludedConnectionIds)); public T Client(string connectionId) { @@ -32,9 +32,9 @@ namespace Microsoft.AspNetCore.SignalR return TypedClientBuilder.Build(_hubClients.Group(groupName)); } - public T GroupExcept(string groupName, IReadOnlyList excludeIds) + public T GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) { - return TypedClientBuilder.Build(_hubClients.GroupExcept(groupName, excludeIds)); + return TypedClientBuilder.Build(_hubClients.GroupExcept(groupName, excludedConnectionIds)); } public T Clients(IReadOnlyList connectionIds) diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedHubMessage.cs b/src/Microsoft.AspNetCore.SignalR.Core/SerializedHubMessage.cs similarity index 98% rename from src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedHubMessage.cs rename to src/Microsoft.AspNetCore.SignalR.Core/SerializedHubMessage.cs index 5b67cbf8b8..5b2d507528 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedHubMessage.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/SerializedHubMessage.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.SignalR.Protocol; -namespace Microsoft.AspNetCore.SignalR.Internal +namespace Microsoft.AspNetCore.SignalR { /// /// This class is designed to support the framework. The API is subject to breaking changes. diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedMessage.cs b/src/Microsoft.AspNetCore.SignalR.Core/SerializedMessage.cs similarity index 91% rename from src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedMessage.cs rename to src/Microsoft.AspNetCore.SignalR.Core/SerializedMessage.cs index e591944b06..cf13afcaa3 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedMessage.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/SerializedMessage.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.SignalR.Internal +namespace Microsoft.AspNetCore.SignalR { public readonly struct SerializedMessage { diff --git a/src/Microsoft.AspNetCore.SignalR.Core/SignalRConnectionBuilderExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Core/SignalRConnectionBuilderExtensions.cs index f2701781a9..8645d2aeff 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/SignalRConnectionBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/SignalRConnectionBuilderExtensions.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.SignalR diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj b/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj index 6578fb5c3a..47f37af697 100644 --- a/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj +++ b/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj @@ -9,6 +9,8 @@ + + diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Protocol/JsonHubProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Protocol/JsonHubProtocol.cs index 5c1c1488e9..919d89399f 100644 --- a/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Protocol/JsonHubProtocol.cs +++ b/src/Microsoft.AspNetCore.SignalR.Protocols.Json/Protocol/JsonHubProtocol.cs @@ -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; diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj b/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj index a4c7cbc0be..f92a2c9aad 100644 --- a/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj +++ b/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj @@ -8,6 +8,8 @@ + + diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Protocol/MessagePackHubProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Protocol/MessagePackHubProtocol.cs index dfd1d98c8f..cc8009045a 100644 --- a/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Protocol/MessagePackHubProtocol.cs +++ b/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Protocol/MessagePackHubProtocol.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisInvocation.cs b/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisInvocation.cs index 7d7a963786..e9cedbd5b0 100644 --- a/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisInvocation.cs +++ b/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisInvocation.cs @@ -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. /// - public IReadOnlyList ExcludedIds { get; } + public IReadOnlyList ExcludedConnectionIds { get; } /// /// Gets the message serialization cache containing serialized payloads for the message. /// public SerializedHubMessage Message { get; } - public RedisInvocation(SerializedHubMessage message, IReadOnlyList excludedIds) + public RedisInvocation(SerializedHubMessage message, IReadOnlyList excludedConnectionIds) { Message = message; - ExcludedIds = excludedIds; + ExcludedConnectionIds = excludedConnectionIds; } - public static RedisInvocation Create(string target, object[] arguments, IReadOnlyList excludedIds = null) + public static RedisInvocation Create(string target, object[] arguments, IReadOnlyList excludedConnectionIds = null) { return new RedisInvocation( new SerializedHubMessage(new InvocationMessage(target, null, arguments)), - excludedIds); + excludedConnectionIds); } } } diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/RedisLog.cs b/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisLog.cs similarity index 98% rename from src/Microsoft.AspNetCore.SignalR.Redis/RedisLog.cs rename to src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisLog.cs index 085133facc..4270e8b035 100644 --- a/src/Microsoft.AspNetCore.SignalR.Redis/RedisLog.cs +++ b/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisLog.cs @@ -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. diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisProtocol.cs index bef0a367be..98dcd8955f 100644 --- a/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisProtocol.cs +++ b/src/Microsoft.AspNetCore.SignalR.Redis/Internal/RedisProtocol.cs @@ -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 excludedIds) + public byte[] WriteInvocation(string methodName, object[] args, IReadOnlyList 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 excludedIds = null; + IReadOnlyList 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 data) diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/RedisDependencyInjectionExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Redis/RedisDependencyInjectionExtensions.cs index 75bc28b017..b8290ce5ed 100644 --- a/src/Microsoft.AspNetCore.SignalR.Redis/RedisDependencyInjectionExtensions.cs +++ b/src/Microsoft.AspNetCore.SignalR.Redis/RedisDependencyInjectionExtensions.cs @@ -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); }); } diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs b/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs index 2dfd5125c0..6c471ce7f8 100644 --- a/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs +++ b/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs @@ -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 excludedIds) + public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList 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 excludedIds) + public override async Task SendGroupExceptAsync(string groupName, string methodName, object[] args, IReadOnlyList 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(); foreach (var groupConnection in group.Connections) { - if (invocation.ExcludedIds?.Contains(groupConnection.ConnectionId) == true) + if (invocation.ExcludedConnectionIds?.Contains(groupConnection.ConnectionId) == true) { continue; } diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/RedisOptions.cs b/src/Microsoft.AspNetCore.SignalR.Redis/RedisOptions.cs index 330c1e5650..b8f95e0e91 100644 --- a/src/Microsoft.AspNetCore.SignalR.Redis/RedisOptions.cs +++ b/src/Microsoft.AspNetCore.SignalR.Redis/RedisOptions.cs @@ -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> Factory { get; set; } + public Func> ConnectionFactory { get; set; } internal async Task 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); } } } diff --git a/src/Microsoft.AspNetCore.SignalR/HubRouteBuilder.cs b/src/Microsoft.AspNetCore.SignalR/HubRouteBuilder.cs index 4d9a798659..573bfec620 100644 --- a/src/Microsoft.AspNetCore.SignalR/HubRouteBuilder.cs +++ b/src/Microsoft.AspNetCore.SignalR/HubRouteBuilder.cs @@ -18,11 +18,6 @@ namespace Microsoft.AspNetCore.SignalR _routes = routes; } - public void MapHub(string path) where THub : Hub - { - MapHub(new PathString(path), configureOptions: null); - } - public void MapHub(PathString path) where THub : Hub { MapHub(path, configureOptions: null); diff --git a/test/Microsoft.AspNetCore.Http.Connections.Tests/HttpConnectionDispatcherTests.cs b/test/Microsoft.AspNetCore.Http.Connections.Tests/HttpConnectionDispatcherTests.cs index 2e96afd7a7..9443099b05 100644 --- a/test/Microsoft.AspNetCore.Http.Connections.Tests/HttpConnectionDispatcherTests.cs +++ b/test/Microsoft.AspNetCore.Http.Connections.Tests/HttpConnectionDispatcherTests.cs @@ -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(); 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(); 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()); - await dispatcher.ExecuteAsync(context, options, app).OrTimeout(); - Assert.NotNull(connection.Features.Get()); - Assert.Equal(options.LongPolling.PollTimeout, connection.Features.Get().KeepAliveInterval); + Assert.True(connection.HasInherentKeepAlive); + + // Check via the feature as well to make sure it's there. + Assert.True(connection.Features.Get().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(); diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.ConnectionLifecycle.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.ConnectionLifecycle.cs index 08710a3228..a115236af8 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.ConnectionLifecycle.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.ConnectionLifecycle.cs @@ -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; diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Transport.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Transport.cs index 7b6bfc4bc8..42839f7472 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Transport.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Transport.cs @@ -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 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(); + 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) => diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/LongPollingTransportTests.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/LongPollingTransportTests.cs index 5e203256f0..ee4c60daac 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/LongPollingTransportTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/LongPollingTransportTests.cs @@ -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(); 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(() => longPollingTransport.StartAsync(TestUri, TransferFormat.Binary)); + Assert.Contains(" 500 ", exception.Message); + } + finally + { + await longPollingTransport.StopAsync(); + } + } + } + + [Fact] + public async Task LongPollingTransportStopsWhenPollRequestFails() + { + var mockHttpHandler = new Mock(); + var firstPoll = true; + mockHttpHandler.Protected() + .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) + .Returns(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(); var sentRequests = new List(); 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(); var tcs = new TaskCompletionSource(); + var firstPoll = true; var mockHttpHandler = new Mock(); 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(); var pollTcs = new TaskCompletionSource(); var deleteTcs = new TaskCompletionSource(); + var firstPoll = true; var mockHttpHandler = new Mock(); 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(); } diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj b/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj index efdeb1d1fc..43229b1bea 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj @@ -6,6 +6,8 @@ + + diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/ResponseUtils.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/ResponseUtils.cs index c23b216ac2..58d5fbb53c 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/ResponseUtils.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/ResponseUtils.cs @@ -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 && diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs index b458330203..2cec05e1db 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs @@ -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; diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestHttpMessageHandler.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestHttpMessageHandler.cs index fc9a7e780b..6bde5d0af2 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestHttpMessageHandler.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestHttpMessageHandler.cs @@ -7,10 +7,14 @@ using System.Threading.Tasks; namespace Microsoft.AspNetCore.SignalR.Client.Tests { + delegate Task RequestDelegate(HttpRequestMessage requestMessage, CancellationToken cancellationToken); + public class TestHttpMessageHandler : HttpMessageHandler { private List _receivedRequests = new List(); - private Func> _handler; + private RequestDelegate _app; + + private List> _middleware = new List>(); public IReadOnlyList 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 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>, CancellationToken, Task> handler) { - var nextHandler = _handler; - _handler = (request, cancellationToken) => handler(request, () => nextHandler(request, cancellationToken), cancellationToken); + void OnRequestCore(Func middleware) + { + _middleware.Add(middleware); + } + + OnRequestCore(next => + { + return (request, cancellationToken) => + { + return handler(request, () => next(request, cancellationToken), cancellationToken); + }; + }); } public void OnGet(string pathAndQuery, Func> handler) => OnRequest(HttpMethod.Get, pathAndQuery, handler); diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageFormatterTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageFormatterTests.cs index 910f8c0818..3f6c4e592a 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageFormatterTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageFormatterTests.cs @@ -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 diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageParserTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageParserTests.cs index ad7139a331..c2f02811e7 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageParserTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/BinaryMessageParserTests.cs @@ -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 diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageFormatterTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageFormatterTests.cs index 43bbfab16d..a444f0108c 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageFormatterTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageFormatterTests.cs @@ -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 diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageParserTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageParserTests.cs index f7a337e174..df6330d833 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageParserTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Formatters/TextMessageParserTests.cs @@ -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 diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs index d71bd7266b..18fea62dd5 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs @@ -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; diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs index ee33493be8..dcfe2b23a1 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs @@ -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 diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj index bc58f85974..585c330599 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj @@ -4,6 +4,11 @@ $(StandardTestTfms) + + + + + PreserveNewest diff --git a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/EchoHub.cs b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/EchoHub.cs index 2ce692906e..ab8000903f 100644 --- a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/EchoHub.cs +++ b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/EchoHub.cs @@ -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); } } } diff --git a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisDependencyInjectionExtensionsTests.cs b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisDependencyInjectionExtensionsTests.cs index 785048e5a2..385bf345d9 100644 --- a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisDependencyInjectionExtensionsTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisDependencyInjectionExtensionsTests.cs @@ -26,16 +26,16 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests var options = provider.GetService>(); 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(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); } } } diff --git a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisHubLifetimeManagerTests.cs b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisHubLifetimeManagerTests.cs index 72f2bf9a18..7335158912 100644 --- a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisHubLifetimeManagerTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisHubLifetimeManagerTests.cs @@ -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 { client2.Connection.ConnectionId }; - await manager.SendGroupExceptAsync("gunit", "Hello", new object[] { "World" }, excludedIds).OrTimeout(); + var excludedConnectionIds = new List { 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 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(); diff --git a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisProtocolTests.cs index 0360928004..7d1a4aa3e4 100644 --- a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisProtocolTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/RedisProtocolTests.cs @@ -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); } diff --git a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/Startup.cs b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/Startup.cs index d43e2ae834..762b729821 100644 --- a/test/Microsoft.AspNetCore.SignalR.Redis.Tests/Startup.cs +++ b/test/Microsoft.AspNetCore.SignalR.Redis.Tests/Startup.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests .AddRedis(options => { // We start the servers before starting redis so we want to time them out ASAP - options.Options.ConnectTimeout = 1; + options.Configuration.ConnectTimeout = 1; }); } diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/ClientProxyTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/ClientProxyTests.cs index 2381590e12..373e5af633 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/ClientProxyTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/ClientProxyTests.cs @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests var o = new Mock>(); o.Setup(m => m.SendGroupExceptAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((groupName, methodName, args, excludedIds) => { resultArgs = args; }) + .Callback>((groupName, methodName, args, excludedConnectionIds) => { resultArgs = args; }) .Returns(Task.CompletedTask); var proxy = new GroupExceptProxy(o.Object, string.Empty, new List()); @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests var o = new Mock>(); o.Setup(m => m.SendAllExceptAsync(It.IsAny(), It.IsAny(), It.IsAny>())) - .Callback>((methodName, args, excludedIds) => { resultArgs = args; }) + .Callback>((methodName, args, excludedConnectionIds) => { resultArgs = args; }) .Returns(Task.CompletedTask); var proxy = new AllClientsExceptProxy(o.Object, new List()); diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubActivatorTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubActivatorTests.cs index e0917698d2..dd75dd3d51 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubActivatorTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubActivatorTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.SignalR.Internal; using Moq; using Moq.Protected; using Xunit; diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubLifetimeManagerTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubLifetimeManagerTests.cs index 8eda3df607..6fcce1872d 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubLifetimeManagerTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/DefaultHubLifetimeManagerTests.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.SignalR.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(); @@ -101,8 +101,8 @@ namespace Microsoft.AspNetCore.SignalR.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(); await manager.SendGroupExceptAsync("gunit", "Hello", new object[] { "World" }, new []{ connection2.ConnectionId }).OrTimeout(); @@ -145,14 +145,14 @@ namespace Microsoft.AspNetCore.SignalR.Tests public async Task AddGroupOnNonExistentConnectionNoops() { var manager = new DefaultHubLifetimeManager(new Logger>(NullLoggerFactory.Instance)); - await manager.AddGroupAsync("NotARealConnectionId", "MyGroup").OrTimeout(); + await manager.AddToGroupAsync("NotARealConnectionId", "MyGroup").OrTimeout(); } [Fact] public async Task RemoveGroupOnNonExistentConnectionNoops() { var manager = new DefaultHubLifetimeManager(new Logger>(NullLoggerFactory.Instance)); - await manager.RemoveGroupAsync("NotARealConnectionId", "MyGroup").OrTimeout(); + await manager.RemoveFromGroupAsync("NotARealConnectionId", "MyGroup").OrTimeout(); } private class MyHub : Hub diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs index da0f3e38c8..62b5fedddf 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs @@ -44,32 +44,44 @@ namespace Microsoft.AspNetCore.SignalR.Tests [Fact] public async Task CanStartAndStopConnectionUsingDefaultTransport() { - var url = ServerFixture.Url + "/echo"; - // The test should connect to the server using WebSockets transport on Windows 8 and newer. - // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server. - var connection = new HttpConnection(new Uri(url)); - await connection.StartAsync(TransferFormat.Binary).OrTimeout(); - await connection.DisposeAsync().OrTimeout(); + using (StartVerifableLog(out var loggerFactory)) + { + var url = ServerFixture.Url + "/echo"; + // The test should connect to the server using WebSockets transport on Windows 8 and newer. + // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server. + var connection = new HttpConnection(new Uri(url), HttpTransports.All, loggerFactory); + await connection.StartAsync(TransferFormat.Binary).OrTimeout(); + await connection.DisposeAsync().OrTimeout(); + } } [Fact] public async Task TransportThatFallsbackCreatesNewConnection() { - var url = ServerFixture.Url + "/echo"; - // The test should connect to the server using WebSockets transport on Windows 8 and newer. - // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server. + bool ExpectedErrors(WriteContext writeContext) + { + return writeContext.LoggerName == typeof(HttpConnection).FullName && + writeContext.EventId.Name == "ErrorStartingTransport"; + } - // The test logic lives in the TestTransportFactory and FakeTransport. - var connection = new HttpConnection(new HttpConnectionOptions { Url = new Uri(url) }, null, new TestTransportFactory()); - await connection.StartAsync(TransferFormat.Text).OrTimeout(); - await connection.DisposeAsync().OrTimeout(); + using (StartVerifableLog(out var loggerFactory, expectedErrorsFilter: ExpectedErrors)) + { + var url = ServerFixture.Url + "/echo"; + // The test should connect to the server using WebSockets transport on Windows 8 and newer. + // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server. + + // The test logic lives in the TestTransportFactory and FakeTransport. + var connection = new HttpConnection(new HttpConnectionOptions { Url = new Uri(url) }, loggerFactory, new TestTransportFactory()); + await connection.StartAsync(TransferFormat.Text).OrTimeout(); + await connection.DisposeAsync().OrTimeout(); + } } [Theory] [MemberData(nameof(TransportTypes))] public async Task CanStartAndStopConnectionUsingGivenTransport(HttpTransportType transportType) { - using (StartVerifableLog(out var loggerFactory, testName: $"CanStartAndStopConnectionUsingGivenTransport_{transportType}", minLogLevel: LogLevel.Trace)) + using (StartVerifableLog(out var loggerFactory, minLogLevel: LogLevel.Trace, testName: $"CanStartAndStopConnectionUsingGivenTransport_{transportType}")) { var url = ServerFixture.Url + "/echo"; var connection = new HttpConnection(new Uri(url), transportType, loggerFactory); @@ -525,7 +537,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests if (_tries < availableTransports) { - throw new Exception(); + return Task.FromException(new Exception()); } else { diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTestUtils/Hubs.cs b/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTestUtils/Hubs.cs index c25070cead..0de1b849bf 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTestUtils/Hubs.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTestUtils/Hubs.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests { public Task GroupRemoveMethod(string groupName) { - return Groups.RemoveAsync(Context.ConnectionId, groupName); + return Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName); } public Task ClientSendMethod(string userId, string message) @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests public Task GroupAddMethod(string groupName) { - return Groups.AddAsync(Context.ConnectionId, groupName); + return Groups.AddToGroupAsync(Context.ConnectionId, groupName); } public Task GroupSendMethod(string groupName, string message) @@ -48,9 +48,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests return Clients.Group(groupName).SendAsync("Send", message); } - public Task GroupExceptSendMethod(string groupName, string message, IReadOnlyList excludedIds) + public Task GroupExceptSendMethod(string groupName, string message, IReadOnlyList excludedConnectionIds) { - return Clients.GroupExcept(groupName, excludedIds).SendAsync("Send", message); + return Clients.GroupExcept(groupName, excludedConnectionIds).SendAsync("Send", message); } public Task SendToMultipleGroups(string message, IReadOnlyList groupNames) @@ -137,9 +137,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests { } - public Task SendToAllExcept(string message, IReadOnlyList excludedIds) + public Task SendToAllExcept(string message, IReadOnlyList excludedConnectionIds) { - return Clients.AllExcept(excludedIds).SendAsync("Send", message); + return Clients.AllExcept(excludedConnectionIds).SendAsync("Send", message); } public bool HasHttpContext() @@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests public Task GroupAddMethod(string groupName) { - return Groups.AddAsync(Context.ConnectionId, groupName); + return Groups.AddToGroupAsync(Context.ConnectionId, groupName); } public Task GroupSendMethod(string groupName, string message) @@ -212,9 +212,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests return Clients.Group(groupName).Send(message); } - public Task GroupExceptSendMethod(string groupName, string message, IReadOnlyList excludedIds) + public Task GroupExceptSendMethod(string groupName, string message, IReadOnlyList excludedConnectionIds) { - return Clients.GroupExcept(groupName, excludedIds).Send(message); + return Clients.GroupExcept(groupName, excludedConnectionIds).Send(message); } public Task SendToOthersInGroup(string groupName, string message) @@ -232,9 +232,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests return Clients.All.Broadcast(message); } - public Task SendToAllExcept(string message, IReadOnlyList excludedIds) + public Task SendToAllExcept(string message, IReadOnlyList excludedConnectionIds) { - return Clients.AllExcept(excludedIds).Send(message); + return Clients.AllExcept(excludedConnectionIds).Send(message); } public Task SendToOthers(string message) @@ -290,7 +290,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests public Task GroupAddMethod(string groupName) { - return Groups.AddAsync(Context.ConnectionId, groupName); + return Groups.AddToGroupAsync(Context.ConnectionId, groupName); } public Task GroupSendMethod(string groupName, string message) @@ -298,9 +298,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests return Clients.Group(groupName).Send(message); } - public Task GroupExceptSendMethod(string groupName, string message, IReadOnlyList excludedIds) + public Task GroupExceptSendMethod(string groupName, string message, IReadOnlyList excludedConnectionIds) { - return Clients.GroupExcept(groupName, excludedIds).Send(message); + return Clients.GroupExcept(groupName, excludedConnectionIds).Send(message); } public Task SendToMultipleGroups(string message, IReadOnlyList groupNames) @@ -318,9 +318,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests return Clients.All.Broadcast(message); } - public Task SendToAllExcept(string message, IReadOnlyList excludedIds) + public Task SendToAllExcept(string message, IReadOnlyList excludedConnectionIds) { - return Clients.AllExcept(excludedIds).Send(message); + return Clients.AllExcept(excludedConnectionIds).Send(message); } public Task SendToOthers(string message) diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs index e84cc14a5a..9076587e92 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs @@ -1156,9 +1156,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests await firstClient.InvokeAsync(nameof(MethodHub.GroupAddMethod), "testGroup").OrTimeout(); await secondClient.InvokeAsync(nameof(MethodHub.GroupAddMethod), "testGroup").OrTimeout(); - var excludedIds = new List { firstClient.Connection.ConnectionId }; + var excludedConnectionIds = new List { firstClient.Connection.ConnectionId }; - await firstClient.SendInvocationAsync("GroupExceptSendMethod", "testGroup", "test", excludedIds).OrTimeout(); + await firstClient.SendInvocationAsync("GroupExceptSendMethod", "testGroup", "test", excludedConnectionIds).OrTimeout(); // check that 'secondConnection' has received the group send var hubMessage = await secondClient.ReadAsync().OrTimeout(); diff --git a/version.props b/version.props index 3cd888d481..573566501b 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 1.0.0 - preview3 + 1.1.0 + preview1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000