Fix SignalR+WebSockets on WASM (#25922)
* Fix SignalR+WebSockets on WASM * fb * move stuff * select
This commit is contained in:
parent
e51468db03
commit
899deacb22
|
|
@ -7,7 +7,9 @@ using BasicTestApp;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||||
using Microsoft.AspNetCore.E2ETesting;
|
using Microsoft.AspNetCore.E2ETesting;
|
||||||
|
using Microsoft.AspNetCore.Http.Connections;
|
||||||
using OpenQA.Selenium;
|
using OpenQA.Selenium;
|
||||||
|
using OpenQA.Selenium.Support.UI;
|
||||||
using TestServer;
|
using TestServer;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
@ -38,13 +40,28 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void SignalRClientWorks()
|
public void SignalRClientWorksWithLongPolling()
|
||||||
{
|
{
|
||||||
Browser.FindElement(By.Id("hub-url")).SendKeys(
|
Browser.FindElement(By.Id("hub-url")).SendKeys(
|
||||||
new Uri(_apiServerFixture.RootUri, "/subdir/chathub").AbsoluteUri);
|
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.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);
|
() => Browser.FindElements(By.CssSelector("li")).FirstOrDefault()?.Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
@using Microsoft.AspNetCore.SignalR.Client
|
@using Microsoft.AspNetCore.SignalR.Client
|
||||||
|
@using Microsoft.AspNetCore.Http.Connections
|
||||||
|
|
||||||
<h1 id="signalr-client">SignalR Client</h1>
|
<h1 id="signalr-client">SignalR Client</h1>
|
||||||
|
|
||||||
|
|
@ -7,6 +8,10 @@
|
||||||
<p>
|
<p>
|
||||||
Hub URL:
|
Hub URL:
|
||||||
<input id="hub-url" @bind="hubUrl" />
|
<input id="hub-url" @bind="hubUrl" />
|
||||||
|
<select id="transport-type" @bind="transportType">
|
||||||
|
<option value=@HttpTransportType.LongPolling>LongPolling</option>
|
||||||
|
<option value=@HttpTransportType.WebSockets>WebSockets</option>
|
||||||
|
</select>
|
||||||
<button id="hub-connect" @onclick="Connect">Connect</button>
|
<button id="hub-connect" @onclick="Connect">Connect</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -21,13 +26,14 @@
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string hubUrl;
|
private string hubUrl;
|
||||||
|
private HttpTransportType transportType;
|
||||||
private HubConnection hubConnection;
|
private HubConnection hubConnection;
|
||||||
private List<string> messages = new List<string>();
|
private List<string> messages = new List<string>();
|
||||||
|
|
||||||
protected async Task Connect()
|
protected async Task Connect()
|
||||||
{
|
{
|
||||||
hubConnection = new HubConnectionBuilder()
|
hubConnection = new HubConnectionBuilder()
|
||||||
.WithUrl(hubUrl)
|
.WithUrl(hubUrl, transportType)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
|
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
|
||||||
|
|
@ -38,7 +44,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
await hubConnection.StartAsync();
|
await hubConnection.StartAsync();
|
||||||
await hubConnection.SendAsync("SendMessage", "SignalR Client", "Echo");
|
await hubConnection.SendAsync("SendMessage", "SignalR Client", $"Echo {transportType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsConnected =>
|
public bool IsConnected =>
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,9 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
||||||
{
|
{
|
||||||
return new WebSocketsTransport(_httpConnectionOptions, _loggerFactory, _accessTokenProvider);
|
return new WebSocketsTransport(_httpConnectionOptions, _loggerFactory, _accessTokenProvider);
|
||||||
}
|
}
|
||||||
catch (PlatformNotSupportedException)
|
catch (PlatformNotSupportedException ex)
|
||||||
{
|
{
|
||||||
|
Log.TransportNotSupported(_loggerFactory.CreateLogger<DefaultTransportFactory>(), HttpTransportType.WebSockets, ex);
|
||||||
_websocketsSupported = false;
|
_websocketsSupported = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,5 +60,16 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
||||||
|
|
||||||
throw new InvalidOperationException("No requested transports available on the server.");
|
throw new InvalidOperationException("No requested transports available on the server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class Log
|
||||||
|
{
|
||||||
|
private static readonly Action<ILogger, HttpTransportType, Exception> _transportNotSupported =
|
||||||
|
LoggerMessage.Define<HttpTransportType>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,66 +37,70 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
||||||
public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func<Task<string>> accessTokenProvider)
|
public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func<Task<string>> accessTokenProvider)
|
||||||
{
|
{
|
||||||
_webSocket = new ClientWebSocket();
|
_webSocket = new ClientWebSocket();
|
||||||
|
_isRunningInBrowser = Utils.IsRunningInBrowser();
|
||||||
|
|
||||||
// Full Framework will throw when trying to set the User-Agent header
|
// ClientWebSocketOptions throws PNSE when accessing and setting properties
|
||||||
// So avoid setting it in netstandard2.0 and only set it in netstandard2.1 and higher
|
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
|
#if !NETSTANDARD2_0
|
||||||
_webSocket.Options.SetRequestHeader("User-Agent", Constants.UserAgentHeader.ToString());
|
_webSocket.Options.SetRequestHeader("User-Agent", Constants.UserAgentHeader.ToString());
|
||||||
#else
|
#else
|
||||||
// Set an alternative user agent header on Full framework
|
// Set an alternative user agent header on Full framework
|
||||||
_webSocket.Options.SetRequestHeader("X-SignalR-User-Agent", Constants.UserAgentHeader.ToString());
|
_webSocket.Options.SetRequestHeader("X-SignalR-User-Agent", Constants.UserAgentHeader.ToString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (httpConnectionOptions != null)
|
if (httpConnectionOptions != null)
|
||||||
{
|
|
||||||
if (httpConnectionOptions.Headers != 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)
|
// 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.ClientCertificates.AddRange(httpConnectionOptions.ClientCertificates);
|
_webSocket.Options.SetRequestHeader("X-Requested-With", "XMLHttpRequest");
|
||||||
}
|
|
||||||
|
|
||||||
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
|
_closeTimeout = httpConnectionOptions?.CloseTimeout ?? default;
|
||||||
// See: https://github.com/aspnet/Security/blob/ff9f145a8e89c9756ea12ff10c6d47f2f7eb345f/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs#L42
|
|
||||||
_webSocket.Options.SetRequestHeader("X-Requested-With", "XMLHttpRequest");
|
|
||||||
|
|
||||||
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WebSocketsTransport>();
|
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WebSocketsTransport>();
|
||||||
|
|
||||||
// Ignore the HttpConnectionOptions access token provider. We were given an updated delegate from the HttpConnection.
|
// Ignore the HttpConnectionOptions access token provider. We were given an updated delegate from the HttpConnection.
|
||||||
_accessTokenProvider = accessTokenProvider;
|
_accessTokenProvider = accessTokenProvider;
|
||||||
|
|
||||||
_isRunningInBrowser = Utils.IsRunningInBrowser();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken = default)
|
public async Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken = default)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue