diff --git a/src/Components/test/E2ETest/Tests/SignalRClientTest.cs b/src/Components/test/E2ETest/Tests/SignalRClientTest.cs
index aa4e82bb1d..e5aa385cc1 100644
--- a/src/Components/test/E2ETest/Tests/SignalRClientTest.cs
+++ b/src/Components/test/E2ETest/Tests/SignalRClientTest.cs
@@ -7,7 +7,9 @@ using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
+using Microsoft.AspNetCore.Http.Connections;
using OpenQA.Selenium;
+using OpenQA.Selenium.Support.UI;
using TestServer;
using Xunit;
using Xunit.Abstractions;
@@ -38,13 +40,28 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
}
[Fact]
- public void SignalRClientWorks()
+ public void SignalRClientWorksWithLongPolling()
{
Browser.FindElement(By.Id("hub-url")).SendKeys(
new Uri(_apiServerFixture.RootUri, "/subdir/chathub").AbsoluteUri);
+ var target = new SelectElement(Browser.FindElement(By.Id("transport-type")));
+ target.SelectByText("LongPolling");
Browser.FindElement(By.Id("hub-connect")).Click();
- Browser.Equal("SignalR Client: Echo",
+ Browser.Equal("SignalR Client: Echo LongPolling",
+ () => Browser.FindElements(By.CssSelector("li")).FirstOrDefault()?.Text);
+ }
+
+ [Fact]
+ public void SignalRClientWorksWithWebSockets()
+ {
+ Browser.FindElement(By.Id("hub-url")).SendKeys(
+ new Uri(_apiServerFixture.RootUri, "/subdir/chathub").AbsoluteUri);
+ var target = new SelectElement(Browser.FindElement(By.Id("transport-type")));
+ target.SelectByText("WebSockets");
+ Browser.FindElement(By.Id("hub-connect")).Click();
+
+ Browser.Equal("SignalR Client: Echo WebSockets",
() => Browser.FindElements(By.CssSelector("li")).FirstOrDefault()?.Text);
}
}
diff --git a/src/Components/test/testassets/BasicTestApp/SignalRClientComponent.razor b/src/Components/test/testassets/BasicTestApp/SignalRClientComponent.razor
index 3f0869ee2d..a8fae272ab 100644
--- a/src/Components/test/testassets/BasicTestApp/SignalRClientComponent.razor
+++ b/src/Components/test/testassets/BasicTestApp/SignalRClientComponent.razor
@@ -1,4 +1,5 @@
@using Microsoft.AspNetCore.SignalR.Client
+@using Microsoft.AspNetCore.Http.Connections
SignalR Client
@@ -7,6 +8,10 @@
Hub URL:
+
@@ -21,13 +26,14 @@
@code {
private string hubUrl;
+ private HttpTransportType transportType;
private HubConnection hubConnection;
private List messages = new List();
protected async Task Connect()
{
hubConnection = new HubConnectionBuilder()
- .WithUrl(hubUrl)
+ .WithUrl(hubUrl, transportType)
.Build();
hubConnection.On("ReceiveMessage", (user, message) =>
@@ -38,7 +44,7 @@
});
await hubConnection.StartAsync();
- await hubConnection.SendAsync("SendMessage", "SignalR Client", "Echo");
+ await hubConnection.SendAsync("SendMessage", "SignalR Client", $"Echo {transportType}");
}
public bool IsConnected =>
diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/DefaultTransportFactory.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/DefaultTransportFactory.cs
index 6e66673ad9..d6295d992a 100644
--- a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/DefaultTransportFactory.cs
+++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/DefaultTransportFactory.cs
@@ -39,8 +39,9 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
return new WebSocketsTransport(_httpConnectionOptions, _loggerFactory, _accessTokenProvider);
}
- catch (PlatformNotSupportedException)
+ catch (PlatformNotSupportedException ex)
{
+ Log.TransportNotSupported(_loggerFactory.CreateLogger(), HttpTransportType.WebSockets, ex);
_websocketsSupported = false;
}
}
@@ -59,5 +60,16 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
throw new InvalidOperationException("No requested transports available on the server.");
}
+
+ private static class Log
+ {
+ private static readonly Action _transportNotSupported =
+ LoggerMessage.Define(LogLevel.Debug, new EventId(1, "TransportNotSupported"), "Transport '{TransportType}' is not supported.");
+
+ public static void TransportNotSupported(ILogger logger, HttpTransportType transportType, Exception ex)
+ {
+ _transportNotSupported(logger, transportType, ex);
+ }
+ }
}
}
diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.cs
index e0b8d08aa0..02c3a9748e 100644
--- a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.cs
+++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.cs
@@ -37,66 +37,70 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func> accessTokenProvider)
{
_webSocket = new ClientWebSocket();
+ _isRunningInBrowser = Utils.IsRunningInBrowser();
- // Full Framework will throw when trying to set the User-Agent header
- // So avoid setting it in netstandard2.0 and only set it in netstandard2.1 and higher
+ // ClientWebSocketOptions throws PNSE when accessing and setting properties
+ if (!_isRunningInBrowser)
+ {
+ // Full Framework will throw when trying to set the User-Agent header
+ // So avoid setting it in netstandard2.0 and only set it in netstandard2.1 and higher
#if !NETSTANDARD2_0
- _webSocket.Options.SetRequestHeader("User-Agent", Constants.UserAgentHeader.ToString());
+ _webSocket.Options.SetRequestHeader("User-Agent", Constants.UserAgentHeader.ToString());
#else
- // Set an alternative user agent header on Full framework
- _webSocket.Options.SetRequestHeader("X-SignalR-User-Agent", Constants.UserAgentHeader.ToString());
+ // Set an alternative user agent header on Full framework
+ _webSocket.Options.SetRequestHeader("X-SignalR-User-Agent", Constants.UserAgentHeader.ToString());
#endif
- if (httpConnectionOptions != null)
- {
- if (httpConnectionOptions.Headers != null)
+ if (httpConnectionOptions != null)
{
- foreach (var header in httpConnectionOptions.Headers)
+ if (httpConnectionOptions.Headers != null)
{
- _webSocket.Options.SetRequestHeader(header.Key, header.Value);
+ foreach (var header in httpConnectionOptions.Headers)
+ {
+ _webSocket.Options.SetRequestHeader(header.Key, header.Value);
+ }
}
+
+ if (httpConnectionOptions.Cookies != null)
+ {
+ _webSocket.Options.Cookies = httpConnectionOptions.Cookies;
+ }
+
+ if (httpConnectionOptions.ClientCertificates != null)
+ {
+ _webSocket.Options.ClientCertificates.AddRange(httpConnectionOptions.ClientCertificates);
+ }
+
+ if (httpConnectionOptions.Credentials != null)
+ {
+ _webSocket.Options.Credentials = httpConnectionOptions.Credentials;
+ }
+
+ if (httpConnectionOptions.Proxy != null)
+ {
+ _webSocket.Options.Proxy = httpConnectionOptions.Proxy;
+ }
+
+ if (httpConnectionOptions.UseDefaultCredentials != null)
+ {
+ _webSocket.Options.UseDefaultCredentials = httpConnectionOptions.UseDefaultCredentials.Value;
+ }
+
+ httpConnectionOptions.WebSocketConfiguration?.Invoke(_webSocket.Options);
}
- if (httpConnectionOptions.Cookies != null)
- {
- _webSocket.Options.Cookies = httpConnectionOptions.Cookies;
- }
- if (httpConnectionOptions.ClientCertificates != null)
- {
- _webSocket.Options.ClientCertificates.AddRange(httpConnectionOptions.ClientCertificates);
- }
-
- if (httpConnectionOptions.Credentials != null)
- {
- _webSocket.Options.Credentials = httpConnectionOptions.Credentials;
- }
-
- if (httpConnectionOptions.Proxy != null)
- {
- _webSocket.Options.Proxy = httpConnectionOptions.Proxy;
- }
-
- if (httpConnectionOptions.UseDefaultCredentials != null)
- {
- _webSocket.Options.UseDefaultCredentials = httpConnectionOptions.UseDefaultCredentials.Value;
- }
-
- httpConnectionOptions.WebSocketConfiguration?.Invoke(_webSocket.Options);
-
- _closeTimeout = httpConnectionOptions.CloseTimeout;
+ // Set this header so the server auth middleware will set an Unauthorized instead of Redirect status code
+ // See: https://github.com/aspnet/Security/blob/ff9f145a8e89c9756ea12ff10c6d47f2f7eb345f/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs#L42
+ _webSocket.Options.SetRequestHeader("X-Requested-With", "XMLHttpRequest");
}
- // Set this header so the server auth middleware will set an Unauthorized instead of Redirect status code
- // See: https://github.com/aspnet/Security/blob/ff9f145a8e89c9756ea12ff10c6d47f2f7eb345f/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs#L42
- _webSocket.Options.SetRequestHeader("X-Requested-With", "XMLHttpRequest");
+ _closeTimeout = httpConnectionOptions?.CloseTimeout ?? default;
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger();
// Ignore the HttpConnectionOptions access token provider. We were given an updated delegate from the HttpConnection.
_accessTokenProvider = accessTokenProvider;
-
- _isRunningInBrowser = Utils.IsRunningInBrowser();
}
public async Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken = default)