diff --git a/clients/ts/signalr/src/HttpConnection.ts b/clients/ts/signalr/src/HttpConnection.ts index 00e3b4db56..638be965aa 100644 --- a/clients/ts/signalr/src/HttpConnection.ts +++ b/clients/ts/signalr/src/HttpConnection.ts @@ -146,6 +146,10 @@ export class HttpConnection implements IConnection { return; } + if ((negotiateResponse as any).ProtocolVersion) { + throw Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."); + } + if (negotiateResponse.url) { url = negotiateResponse.url; } diff --git a/clients/ts/signalr/tests/HttpConnection.test.ts b/clients/ts/signalr/tests/HttpConnection.test.ts index a3c635c983..4e4d5c8b7a 100644 --- a/clients/ts/signalr/tests/HttpConnection.test.ts +++ b/clients/ts/signalr/tests/HttpConnection.test.ts @@ -794,5 +794,38 @@ describe("HttpConnection", () => { expect(() => connection.start(42)).toThrowError("Unknown transferFormat value: 42."); }); }); + + it("throws if trying to connect to an ASP.NET SignalR Server", async () => { + await VerifyLogger.run(async (logger) => { + const options: IHttpConnectionOptions = { + ...commonOptions, + httpClient: new TestHttpClient() + .on("POST", () => "{\"Url\":\"/signalr\"," + + "\"ConnectionToken\":\"X97dw3uxW4NPPggQsYVcNcyQcuz4w2\"," + + "\"ConnectionId\":\"05265228-1e2c-46c5-82a1-6a5bcc3f0143\"," + + "\"KeepAliveTimeout\":10.0," + + "\"DisconnectTimeout\":5.0," + + "\"TryWebSockets\":true," + + "\"ProtocolVersion\":\"1.5\"," + + "\"TransportConnectTimeout\":30.0," + + "\"LongPollDelay\":0.0}") + .on("GET", () => ""), + logger, + } as IHttpConnectionOptions; + + const connection = new HttpConnection("http://tempuri.org", options); + let receivedError = false; + try { + await connection.start(TransferFormat.Text); + } catch (error) { + expect(error).toEqual(new Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.")); + receivedError = true; + } finally { + await connection.stop(); + } + expect(receivedError).toBe(true); + }, + "Failed to start the connection: Error: Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."); + }); }); }); diff --git a/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs b/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs index 0102da6ae2..f0c88ecdb1 100644 --- a/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs +++ b/src/Microsoft.AspNetCore.Http.Connections.Common/NegotiateProtocol.cs @@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore.Http.Connections private const string AvailableTransportsPropertyName = "availableTransports"; private const string TransportPropertyName = "transport"; private const string TransferFormatsPropertyName = "transferFormats"; + // Used to detect ASP.NET SignalR Server connection attempt + private const string ProtocolVersionPropertyName = "ProtocolVersion"; public static void WriteResponse(NegotiationResponse response, IBufferWriter output) { @@ -134,6 +136,8 @@ namespace Microsoft.AspNetCore.Http.Connections } } break; + case ProtocolVersionPropertyName: + throw new InvalidOperationException("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."); default: reader.Skip(); break; diff --git a/test/Microsoft.AspNetCore.Http.Connections.Tests/NegotiateProtocolTests.cs b/test/Microsoft.AspNetCore.Http.Connections.Tests/NegotiateProtocolTests.cs index b959e3b44e..39d21610e7 100644 --- a/test/Microsoft.AspNetCore.Http.Connections.Tests/NegotiateProtocolTests.cs +++ b/test/Microsoft.AspNetCore.Http.Connections.Tests/NegotiateProtocolTests.cs @@ -55,6 +55,27 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests Assert.Equal(expectedMessage, exception.InnerException.Message); } + [Fact] + public void ParsingAspNetSignalRResponseThrowsError() + { + var payload = "{\"Url\":\"/signalr\"," + + "\"ConnectionToken\":\"X97dw3uxW4NPPggQsYVcNcyQcuz4w2\"," + + "\"ConnectionId\":\"05265228-1e2c-46c5-82a1-6a5bcc3f0143\"," + + "\"KeepAliveTimeout\":10.0," + + "\"DisconnectTimeout\":5.0," + + "\"TryWebSockets\":true," + + "\"ProtocolVersion\":\"1.5\"," + + "\"TransportConnectTimeout\":30.0," + + "\"LongPollDelay\":0.0}"; + + var responseData = Encoding.UTF8.GetBytes(payload); + var ms = new MemoryStream(responseData); + + var exception = Assert.Throws(() => NegotiateProtocol.ParseResponse(ms)); + + Assert.Equal("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.", exception.InnerException.Message); + } + [Fact] public void WriteNegotiateResponseWithNullAvailableTransports() { diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Negotiate.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Negotiate.cs index 4063af1984..8b0a90b148 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Negotiate.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.Negotiate.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests } [Fact] - public async Task NegotiateReturnedConenctionIdIsSetOnConnection() + public async Task NegotiateReturnedConnectionIdIsSetOnConnection() { string connectionId = null; @@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests testHttpHandler.OnLongPoll((token) => { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - + token.Register(() => tcs.TrySetResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent))); return tcs.Task;