diff --git a/global.json b/global.json index 8efcac913bea..ea54b3a4a7fc 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "5.0.100-rc.1.20452.10" + "version": "6.0.100-alpha.1.20472.11" }, "tools": { - "dotnet": "5.0.100-rc.1.20452.10", + "dotnet": "6.0.100-alpha.1.20472.11", "runtimes": { "dotnet/x64": [ "2.1.18", diff --git a/src/Shared/OperatingSystem.cs b/src/Shared/OperatingSystem.cs new file mode 100644 index 000000000000..e9ca7a717296 --- /dev/null +++ b/src/Shared/OperatingSystem.cs @@ -0,0 +1,19 @@ +// 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. + +#if NETCOREAPP +#error Use System.OperatingSystem instead. +#else + +using System.Runtime.InteropServices; + +namespace Microsoft.AspNetCore +{ + internal sealed class OperatingSystem + { + private static readonly bool _isBrowser = RuntimeInformation.IsOSPlatform(OSPlatform.Create("browser")); + + public static bool IsBrowser() => _isBrowser; + } +} +#endif diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs index c6e2878f2f36..6352e3ede330 100644 --- a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs +++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs @@ -1459,7 +1459,7 @@ private async Task ReconnectAsync(Exception closeException) private OperationCanceledException GetOperationCanceledException(string message, Exception innerException, CancellationToken cancellationToken) { -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NETCOREAPP return new OperationCanceledException(message, innerException, _state.StopCts.Token); #else return new OperationCanceledException(message, innerException); diff --git a/src/SignalR/clients/csharp/Client.Core/src/Microsoft.AspNetCore.SignalR.Client.Core.csproj b/src/SignalR/clients/csharp/Client.Core/src/Microsoft.AspNetCore.SignalR.Client.Core.csproj index 3fd4728dc69a..422af4542721 100644 --- a/src/SignalR/clients/csharp/Client.Core/src/Microsoft.AspNetCore.SignalR.Client.Core.csproj +++ b/src/SignalR/clients/csharp/Client.Core/src/Microsoft.AspNetCore.SignalR.Client.Core.csproj @@ -2,7 +2,7 @@ Client for ASP.NET Core SignalR - $(DefaultNetFxTargetFramework);netstandard2.0;netstandard2.1 + $(DefaultNetCoreTargetFramework);$(DefaultNetFxTargetFramework);netstandard2.0;netstandard2.1 Microsoft.AspNetCore.SignalR.Client @@ -38,4 +38,8 @@ + + + + diff --git a/src/SignalR/clients/csharp/Client/src/Microsoft.AspNetCore.SignalR.Client.csproj b/src/SignalR/clients/csharp/Client/src/Microsoft.AspNetCore.SignalR.Client.csproj index 47444465b45f..594f04355836 100644 --- a/src/SignalR/clients/csharp/Client/src/Microsoft.AspNetCore.SignalR.Client.csproj +++ b/src/SignalR/clients/csharp/Client/src/Microsoft.AspNetCore.SignalR.Client.csproj @@ -1,8 +1,8 @@ - + Client for ASP.NET Core SignalR - $(DefaultNetFxTargetFramework);netstandard2.0 + $(DefaultNetCoreTargetFramework);$(DefaultNetFxTargetFramework);netstandard2.0 @@ -14,4 +14,8 @@ + + + + diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs index 1af8f917f82d..8eb9e2ff15dc 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Net.Http; using System.Net.WebSockets; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; @@ -38,7 +39,6 @@ public partial class HttpConnection : ConnectionContext, IConnectionInherentKeep private bool _started; private bool _disposed; private bool _hasInherentKeepAlive; - private bool _isRunningInBrowser; private readonly HttpClient _httpClient; private readonly HttpConnectionOptions _httpConnectionOptions; @@ -152,9 +152,7 @@ public HttpConnection(HttpConnectionOptions httpConnectionOptions, ILoggerFactor _httpClient = CreateHttpClient(); } - _isRunningInBrowser = Utils.IsRunningInBrowser(); - - if (httpConnectionOptions.Transports == HttpTransportType.ServerSentEvents && _isRunningInBrowser) + if (httpConnectionOptions.Transports == HttpTransportType.ServerSentEvents && OperatingSystem.IsBrowser()) { throw new ArgumentException("ServerSentEvents can not be the only transport specified when running in the browser.", nameof(httpConnectionOptions)); } @@ -376,7 +374,7 @@ private async Task SelectAndStartTransport(TransferFormat transferFormat, Cancel continue; } - if (transportType == HttpTransportType.ServerSentEvents && _isRunningInBrowser) + if (transportType == HttpTransportType.ServerSentEvents && OperatingSystem.IsBrowser()) { Log.ServerSentEventsNotSupportedByBrowser(_logger); transportExceptions.Add(new TransportFailedException("ServerSentEvents", "The transport is not supported in the browser.")); @@ -529,42 +527,49 @@ private HttpClient CreateHttpClient() var httpClientHandler = new HttpClientHandler(); HttpMessageHandler httpMessageHandler = httpClientHandler; + var isBrowser = OperatingSystem.IsBrowser(); + if (_httpConnectionOptions != null) { - if (_httpConnectionOptions.Proxy != null) + if (!isBrowser) { - httpClientHandler.Proxy = _httpConnectionOptions.Proxy; - } + // Configure options that do not work in the browser inside this if-block + if (_httpConnectionOptions.Proxy != null) + { + httpClientHandler.Proxy = _httpConnectionOptions.Proxy; + } - try - { - // On supported platforms, we need to pass the cookie container to the http client - // so that we can capture any cookies from the negotiate response and give them to WebSockets. - httpClientHandler.CookieContainer = _httpConnectionOptions.Cookies; - } - // Some variants of Mono do not support client certs or cookies and will throw NotImplementedException or NotSupportedException - // Also WASM doesn't support some settings in the browser - catch (Exception ex) when (ex is NotSupportedException || ex is NotImplementedException) - { - Log.CookiesNotSupported(_logger); - } + try + { + // On supported platforms, we need to pass the cookie container to the http client + // so that we can capture any cookies from the negotiate response and give them to WebSockets. + httpClientHandler.CookieContainer = _httpConnectionOptions.Cookies; + } + catch (Exception ex) when (ex is NotSupportedException || ex is NotImplementedException) + { + // Some variants of Mono do not support client certs or cookies and will throw NotImplementedException or NotSupportedException + Log.CookiesNotSupported(_logger); + } - // Only access HttpClientHandler.ClientCertificates - // if the user has configured those options - // https://github.com/aspnet/SignalR/issues/2232 - var clientCertificates = _httpConnectionOptions.ClientCertificates; - if (clientCertificates?.Count > 0) - { - httpClientHandler.ClientCertificates.AddRange(clientCertificates); - } + // Only access HttpClientHandler.ClientCertificates + // if the user has configured those options + // https://github.com/aspnet/SignalR/issues/2232 - if (_httpConnectionOptions.UseDefaultCredentials != null) - { - httpClientHandler.UseDefaultCredentials = _httpConnectionOptions.UseDefaultCredentials.Value; - } - if (_httpConnectionOptions.Credentials != null) - { - httpClientHandler.Credentials = _httpConnectionOptions.Credentials; + var clientCertificates = _httpConnectionOptions.ClientCertificates; + if (clientCertificates?.Count > 0) + { + httpClientHandler.ClientCertificates.AddRange(clientCertificates); + } + + if (_httpConnectionOptions.UseDefaultCredentials != null) + { + httpClientHandler.UseDefaultCredentials = _httpConnectionOptions.UseDefaultCredentials.Value; + } + + if (_httpConnectionOptions.Credentials != null) + { + httpClientHandler.Credentials = _httpConnectionOptions.Credentials; + } } httpMessageHandler = httpClientHandler; @@ -645,7 +650,7 @@ private void CheckDisposed() private static bool IsWebSocketsSupported() { -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NETCOREAPP // .NET Core 2.1 and above has a managed implementation return true; #else diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionFactory.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionFactory.cs index cb3ca3d28ab8..6c26c84e71f4 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionFactory.cs +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionFactory.cs @@ -3,6 +3,7 @@ using System; using System.Net; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; @@ -86,23 +87,22 @@ internal static HttpConnectionOptions ShallowCopyHttpConnectionOptions(HttpConne { HttpMessageHandlerFactory = options.HttpMessageHandlerFactory, Headers = options.Headers, - Cookies = options.Cookies, Url = options.Url, Transports = options.Transports, SkipNegotiation = options.SkipNegotiation, AccessTokenProvider = options.AccessTokenProvider, CloseTimeout = options.CloseTimeout, - Credentials = options.Credentials, - Proxy = options.Proxy, - UseDefaultCredentials = options.UseDefaultCredentials, DefaultTransferFormat = options.DefaultTransferFormat, - WebSocketConfiguration = options.WebSocketConfiguration, }; - // WASM doesn't support Crypto APIs and our setter throws if you try to assign null - if (options.ClientCertificates != null) + if (!OperatingSystem.IsBrowser()) { + newOptions.Cookies = options.Cookies; newOptions.ClientCertificates = options.ClientCertificates; + newOptions.Credentials = options.Credentials; + newOptions.Proxy = options.Proxy; + newOptions.UseDefaultCredentials = options.UseDefaultCredentials; + newOptions.WebSocketConfiguration = options.WebSocketConfiguration; } return newOptions; diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionOptions.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionOptions.cs index cfbe155e9b0c..523a34ed0611 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionOptions.cs +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnectionOptions.cs @@ -6,11 +6,12 @@ using System.Net; using System.Net.Http; using System.Net.WebSockets; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; -using Microsoft.AspNetCore.Http.Connections.Client.Internal; namespace Microsoft.AspNetCore.Http.Connections.Client { @@ -22,6 +23,10 @@ public class HttpConnectionOptions private IDictionary _headers; private X509CertificateCollection _clientCertificates; private CookieContainer _cookies; + private ICredentials _credentials; + private IWebProxy _proxy; + private bool? _useDefaultCredentials; + private Action _webSocketConfiguration; /// /// Initializes a new instance of the class. @@ -31,7 +36,7 @@ public HttpConnectionOptions() _headers = new Dictionary(); // System.Security.Cryptography isn't supported on WASM currently - if (!Utils.IsRunningInBrowser()) + if (!OperatingSystem.IsBrowser()) { _clientCertificates = new X509CertificateCollection(); } @@ -59,19 +64,37 @@ public IDictionary Headers /// /// Gets or sets a collection of client certificates that will be sent with HTTP requests. /// + [UnsupportedOSPlatform("browser")] public X509CertificateCollection ClientCertificates { - get => _clientCertificates; - set => _clientCertificates = value ?? throw new ArgumentNullException(nameof(value)); + get + { + ThrowIfUnsupportedPlatform(); + return _clientCertificates; + } + set + { + ThrowIfUnsupportedPlatform(); + _clientCertificates = value ?? throw new ArgumentNullException(nameof(value)); + } } /// /// Gets or sets a collection of cookies that will be sent with HTTP requests. /// + [UnsupportedOSPlatform("browser")] public CookieContainer Cookies { - get => _cookies; - set => _cookies = value ?? throw new ArgumentNullException(nameof(value)); + get + { + ThrowIfUnsupportedPlatform(); + return _cookies; + } + set + { + ThrowIfUnsupportedPlatform(); + _cookies = value ?? throw new ArgumentNullException(nameof(value)); + } } /// @@ -105,17 +128,56 @@ public CookieContainer Cookies /// /// Gets or sets the credentials used when making HTTP requests. /// - public ICredentials Credentials { get; set; } + [UnsupportedOSPlatform("browser")] + public ICredentials Credentials + { + get + { + ThrowIfUnsupportedPlatform(); + return _credentials; + } + set + { + ThrowIfUnsupportedPlatform(); + _credentials = value; + } + } /// /// Gets or sets the proxy used when making HTTP requests. /// - public IWebProxy Proxy { get; set; } + [UnsupportedOSPlatform("browser")] + public IWebProxy Proxy + { + get + { + ThrowIfUnsupportedPlatform(); + return _proxy; + } + set + { + ThrowIfUnsupportedPlatform(); + _proxy = value; + } + } /// /// Gets or sets a value indicating whether default credentials are used when making HTTP requests. /// - public bool? UseDefaultCredentials { get; set; } + [UnsupportedOSPlatform("browser")] + public bool? UseDefaultCredentials + { + get + { + ThrowIfUnsupportedPlatform(); + return _useDefaultCredentials; + } + set + { + ThrowIfUnsupportedPlatform(); + _useDefaultCredentials = value; + } + } /// /// Gets or sets the default to use if @@ -131,6 +193,27 @@ public CookieContainer Cookies /// This delegate is invoked after headers from and the access token from /// has been applied. /// - public Action WebSocketConfiguration { get; set; } + [UnsupportedOSPlatform("browser")] + public Action WebSocketConfiguration + { + get + { + ThrowIfUnsupportedPlatform(); + return _webSocketConfiguration; + } + set + { + ThrowIfUnsupportedPlatform(); + _webSocketConfiguration = value; + } + } + + private static void ThrowIfUnsupportedPlatform() + { + if (OperatingSystem.IsBrowser()) + { + throw new PlatformNotSupportedException(); + } + } } } diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/LongPollingTransport.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/LongPollingTransport.cs index e9f5b21a5be2..902f823e87f8 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/LongPollingTransport.cs +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/LongPollingTransport.cs @@ -5,11 +5,13 @@ using System.IO.Pipelines; using System.Net; using System.Net.Http; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using static Microsoft.AspNetCore.Http.Connections.Client.Internal.Utils; namespace Microsoft.AspNetCore.Http.Connections.Client.Internal { @@ -161,7 +163,7 @@ private async Task Poll(Uri pollUrl, CancellationToken cancellationToken) // just want to start a new poll. continue; } - catch (WebException ex) when (ex.Status == WebExceptionStatus.RequestCanceled) + catch (WebException ex) when (!OperatingSystem.IsBrowser() && ex.Status == WebExceptionStatus.RequestCanceled) { // SendAsync on .NET Framework doesn't reliably throw OperationCanceledException. // Catch the WebException and test it. diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/Utils.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/Utils.cs index 8071a054a3ab..f92f89a3a044 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/Utils.cs +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/Utils.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Http.Connections.Client.Internal { @@ -42,10 +41,5 @@ internal static Uri AppendQueryString(Uri url, string qs) builder.Query = newQueryString; return builder.Uri; } - - internal static bool IsRunningInBrowser() - { - return RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")); - } } } diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.Log.cs b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.Log.cs index 5012d65d64df..a7d110cf244a 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.Log.cs +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.Log.cs @@ -69,6 +69,12 @@ private static class Log private static readonly Action _startedTransport = LoggerMessage.Define(LogLevel.Debug, new EventId(19, "StartedTransport"), "Started transport."); + private static readonly Action _headersNotSupported = + LoggerMessage.Define(LogLevel.Warning, new EventId(20, "HeadersNotSupported"), + $"Configuring request headers using {nameof(HttpConnectionOptions)}.{nameof(HttpConnectionOptions.Headers)} is not supported when using websockets transport " + + "on the browser platform."); + + public static void StartTransport(ILogger logger, TransferFormat transferFormat, Uri webSocketUrl) { _startTransport(logger, transferFormat, webSocketUrl, null); @@ -163,6 +169,11 @@ public static void StartedTransport(ILogger logger) { _startedTransport(logger, null); } + + public static void HeadersNotSupported(ILogger logger) + { + _headersNotSupported(logger, null); + } } } } 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 02c3a9748e2d..dde6c5e01611 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 @@ -24,7 +24,6 @@ internal partial class WebSocketsTransport : ITransport private readonly ILogger _logger; private readonly TimeSpan _closeTimeout; private volatile bool _aborted; - private bool _isRunningInBrowser; private IDuplexPipe _transport; @@ -37,10 +36,8 @@ internal partial class WebSocketsTransport : ITransport public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func> accessTokenProvider) { _webSocket = new ClientWebSocket(); - _isRunningInBrowser = Utils.IsRunningInBrowser(); - - // ClientWebSocketOptions throws PNSE when accessing and setting properties - if (!_isRunningInBrowser) + var isBrowser = OperatingSystem.IsBrowser(); + if (!isBrowser) { // 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 @@ -51,16 +48,30 @@ public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerF _webSocket.Options.SetRequestHeader("X-SignalR-User-Agent", Constants.UserAgentHeader.ToString()); #endif - if (httpConnectionOptions != 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.SetRequestHeader("X-Requested-With", "XMLHttpRequest"); + } + + if (httpConnectionOptions != null) + { + if (httpConnectionOptions.Headers.Count > 0) { - if (httpConnectionOptions.Headers != null) + if (isBrowser) + { + Log.HeadersNotSupported(_logger); + } + else { foreach (var header in httpConnectionOptions.Headers) { _webSocket.Options.SetRequestHeader(header.Key, header.Value); } } + } + if (!isBrowser) + { if (httpConnectionOptions.Cookies != null) { _webSocket.Options.Cookies = httpConnectionOptions.Cookies; @@ -88,11 +99,6 @@ public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerF httpConnectionOptions.WebSocketConfiguration?.Invoke(_webSocket.Options); } - - - // 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; @@ -128,7 +134,7 @@ public async Task StartAsync(Uri url, TransferFormat transferFormat, Cancellatio if (!string.IsNullOrEmpty(accessToken)) { // We can't use request headers in the browser, so instead append the token as a query string in that case - if (_isRunningInBrowser) + if (OperatingSystem.IsBrowser()) { var accessTokenEncoded = UrlEncoder.Default.Encode(accessToken); accessTokenEncoded = "access_token=" + accessTokenEncoded; @@ -136,7 +142,9 @@ public async Task StartAsync(Uri url, TransferFormat transferFormat, Cancellatio } else { +#pragma warning disable CA1416 // Analyzer bug _webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}"); +#pragma warning restore CA1416 // Analyzer bug } } } @@ -228,7 +236,7 @@ private async Task StartReceiving(WebSocket socket) { while (true) { -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NETCOREAPP // Do a 0 byte read so that idle connections don't allocate a buffer when waiting for a read var result = await socket.ReceiveAsync(Memory.Empty, CancellationToken.None); @@ -245,7 +253,7 @@ private async Task StartReceiving(WebSocket socket) } #endif var memory = _application.Output.GetMemory(); -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NETCOREAPP // Because we checked the CloseStatus from the 0 byte read above, we don't need to check again after reading var receiveResult = await socket.ReceiveAsync(memory, CancellationToken.None); #elif NETSTANDARD2_0 || NET461 diff --git a/src/SignalR/clients/csharp/Http.Connections.Client/src/Microsoft.AspNetCore.Http.Connections.Client.csproj b/src/SignalR/clients/csharp/Http.Connections.Client/src/Microsoft.AspNetCore.Http.Connections.Client.csproj index bae3bab800ac..840c26e9a10a 100644 --- a/src/SignalR/clients/csharp/Http.Connections.Client/src/Microsoft.AspNetCore.Http.Connections.Client.csproj +++ b/src/SignalR/clients/csharp/Http.Connections.Client/src/Microsoft.AspNetCore.Http.Connections.Client.csproj @@ -2,7 +2,7 @@ Client for ASP.NET Core Connection Handlers - $(DefaultNetFxTargetFramework);netstandard2.0;netstandard2.1 + $(DefaultNetCoreTargetFramework);$(DefaultNetFxTargetFramework);netstandard2.0;netstandard2.1 @@ -11,6 +11,8 @@ + + @@ -31,4 +33,8 @@ + + + + diff --git a/src/SignalR/common/Http.Connections.Common/src/Microsoft.AspNetCore.Http.Connections.Common.csproj b/src/SignalR/common/Http.Connections.Common/src/Microsoft.AspNetCore.Http.Connections.Common.csproj index 02f97edfb68c..a6327955968f 100644 --- a/src/SignalR/common/Http.Connections.Common/src/Microsoft.AspNetCore.Http.Connections.Common.csproj +++ b/src/SignalR/common/Http.Connections.Common/src/Microsoft.AspNetCore.Http.Connections.Common.csproj @@ -23,4 +23,8 @@ + + + + diff --git a/src/SignalR/common/Http.Connections/src/Microsoft.AspNetCore.Http.Connections.csproj b/src/SignalR/common/Http.Connections/src/Microsoft.AspNetCore.Http.Connections.csproj index 314ab57e6e36..9497a7c8ac8f 100644 --- a/src/SignalR/common/Http.Connections/src/Microsoft.AspNetCore.Http.Connections.csproj +++ b/src/SignalR/common/Http.Connections/src/Microsoft.AspNetCore.Http.Connections.csproj @@ -42,4 +42,8 @@ + + + + diff --git a/src/SignalR/common/Protocols.Json/src/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj b/src/SignalR/common/Protocols.Json/src/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj index cae05aae1122..34a5f17dd19d 100644 --- a/src/SignalR/common/Protocols.Json/src/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj +++ b/src/SignalR/common/Protocols.Json/src/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj @@ -23,4 +23,8 @@ + + + + diff --git a/src/SignalR/common/Protocols.MessagePack/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj b/src/SignalR/common/Protocols.MessagePack/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj index 8ed07be5dcdc..69554b03f11a 100644 --- a/src/SignalR/common/Protocols.MessagePack/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj +++ b/src/SignalR/common/Protocols.MessagePack/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj @@ -2,7 +2,7 @@ Implements the SignalR Hub Protocol over MsgPack. - $(DefaultNetFxTargetFramework);netstandard2.0 + $(DefaultNetCoreTargetFramework);$(DefaultNetFxTargetFramework);netstandard2.0 Microsoft.AspNetCore.SignalR true enable @@ -20,4 +20,8 @@ + + + + diff --git a/src/SignalR/common/Protocols.MessagePack/src/Protocol/MessagePackHubProtocolWorker.cs b/src/SignalR/common/Protocols.MessagePack/src/Protocol/MessagePackHubProtocolWorker.cs index 43c9a8392980..6c36e33751d3 100644 --- a/src/SignalR/common/Protocols.MessagePack/src/Protocol/MessagePackHubProtocolWorker.cs +++ b/src/SignalR/common/Protocols.MessagePack/src/Protocol/MessagePackHubProtocolWorker.cs @@ -21,7 +21,7 @@ internal abstract class MessagePackHubProtocolWorker private const int VoidResult = 2; private const int NonVoidResult = 3; - public bool TryParseMessage(ref ReadOnlySequence input, IInvocationBinder binder, out HubMessage message) + public bool TryParseMessage(ref ReadOnlySequence input, IInvocationBinder binder, out HubMessage? message) { if (!BinaryMessageParser.TryParseMessage(ref input, out var payload)) { @@ -34,7 +34,7 @@ public bool TryParseMessage(ref ReadOnlySequence input, IInvocationBinder return true; } - private HubMessage ParseMessage(ref MessagePackReader reader, IInvocationBinder binder) + private HubMessage? ParseMessage(ref MessagePackReader reader, IInvocationBinder binder) { var itemCount = reader.ReadArrayHeader(); @@ -76,7 +76,7 @@ private HubMessage CreateInvocationMessage(ref MessagePackReader reader, IInvoca var target = ReadString(ref reader, "target"); - object[] arguments = null; + object[]? arguments; try { var parameterTypes = binder.GetParameterTypes(target); @@ -87,7 +87,7 @@ private HubMessage CreateInvocationMessage(ref MessagePackReader reader, IInvoca return new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex)); } - string[] streams = null; + string[]? streams = null; // Previous clients will send 5 items, so we check if they sent a stream array or not if (itemCount > 5) { @@ -103,7 +103,7 @@ private HubMessage CreateStreamInvocationMessage(ref MessagePackReader reader, I var invocationId = ReadInvocationId(ref reader); var target = ReadString(ref reader, "target"); - object[] arguments = null; + object[] arguments; try { var parameterTypes = binder.GetParameterTypes(target); @@ -114,7 +114,7 @@ private HubMessage CreateStreamInvocationMessage(ref MessagePackReader reader, I return new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex)); } - string[] streams = null; + string[]? streams = null; // Previous clients will send 5 items, so we check if they sent a stream array or not if (itemCount > 5) { @@ -148,8 +148,8 @@ private CompletionMessage CreateCompletionMessage(ref MessagePackReader reader, var invocationId = ReadInvocationId(ref reader); var resultKind = ReadInt32(ref reader, "resultKind"); - string error = null; - object result = null; + string? error = null; + object? result = null; var hasResult = false; switch (resultKind) @@ -198,7 +198,7 @@ private CloseMessage CreateCloseMessage(ref MessagePackReader reader, int itemCo return new CloseMessage(error, allowReconnect); } - private Dictionary ReadHeaders(ref MessagePackReader reader) + private Dictionary? ReadHeaders(ref MessagePackReader reader) { var headerCount = ReadMapLength(ref reader, "headers"); if (headerCount > 0) @@ -219,10 +219,10 @@ private Dictionary ReadHeaders(ref MessagePackReader reader) } } - private string[] ReadStreamIds(ref MessagePackReader reader) + private string[]? ReadStreamIds(ref MessagePackReader reader) { var streamIdCount = ReadArrayLength(ref reader, "streamIds"); - List streams = null; + List? streams = null; if (streamIdCount > 0) { @@ -264,7 +264,7 @@ private object[] BindArguments(ref MessagePackReader reader, IReadOnlyList protected abstract object DeserializeObject(ref MessagePackReader reader, Type type, string field); - private T ApplyHeaders(IDictionary source, T destination) where T : HubInvocationMessage + private T ApplyHeaders(IDictionary? source, T destination) where T : HubInvocationMessage { if (source != null && source.Count > 0) { @@ -374,10 +374,18 @@ private void WriteInvocationMessage(InvocationMessage message, ref MessagePackWr writer.Write(message.InvocationId); } writer.Write(message.Target); - writer.WriteArrayHeader(message.Arguments.Length); - foreach (var arg in message.Arguments) + + if (message.Arguments is null) { - WriteArgument(arg, ref writer); + writer.WriteArrayHeader(0); + } + else + { + writer.WriteArrayHeader(message.Arguments.Length); + foreach (var arg in message.Arguments) + { + WriteArgument(arg, ref writer); + } } WriteStreamIds(message.StreamIds, ref writer); @@ -392,10 +400,17 @@ private void WriteStreamInvocationMessage(StreamInvocationMessage message, ref M writer.Write(message.InvocationId); writer.Write(message.Target); - writer.WriteArrayHeader(message.Arguments.Length); - foreach (var arg in message.Arguments) + if (message.Arguments is null) { - WriteArgument(arg, ref writer); + writer.WriteArrayHeader(0); + } + else + { + writer.WriteArrayHeader(message.Arguments.Length); + foreach (var arg in message.Arguments) + { + WriteArgument(arg, ref writer); + } } WriteStreamIds(message.StreamIds, ref writer); @@ -410,7 +425,7 @@ private void WriteStreamingItemMessage(StreamItemMessage message, ref MessagePac WriteArgument(message.Item, ref writer); } - private void WriteArgument(object argument, ref MessagePackWriter writer) + private void WriteArgument(object? argument, ref MessagePackWriter writer) { if (argument == null) { @@ -424,7 +439,7 @@ private void WriteArgument(object argument, ref MessagePackWriter writer) protected abstract void Serialize(ref MessagePackWriter writer, Type type, object value); - private void WriteStreamIds(string[] streamIds, ref MessagePackWriter writer) + private void WriteStreamIds(string[]? streamIds, ref MessagePackWriter writer) { if (streamIds != null) { @@ -493,7 +508,7 @@ private void WritePingMessage(PingMessage pingMessage, ref MessagePackWriter wri writer.Write(HubProtocolConstants.PingMessageType); } - private void PackHeaders(IDictionary headers, ref MessagePackWriter writer) + private void PackHeaders(IDictionary? headers, ref MessagePackWriter writer) { if (headers != null) { diff --git a/src/SignalR/common/Protocols.NewtonsoftJson/src/Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj b/src/SignalR/common/Protocols.NewtonsoftJson/src/Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj index 00e59a9ceef2..51d392697c8d 100644 --- a/src/SignalR/common/Protocols.NewtonsoftJson/src/Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj +++ b/src/SignalR/common/Protocols.NewtonsoftJson/src/Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj @@ -2,7 +2,7 @@ Implements the SignalR Hub Protocol using Newtonsoft.Json. - $(DefaultNetFxTargetFramework);netstandard2.0 + $(DefaultNetCoreTargetFramework);$(DefaultNetFxTargetFramework);netstandard2.0 Microsoft.AspNetCore.SignalR true enable @@ -21,4 +21,8 @@ + + + + diff --git a/src/SignalR/common/Shared/JsonUtils.cs b/src/SignalR/common/Shared/JsonUtils.cs index 22a369047004..f1591cae84c1 100644 --- a/src/SignalR/common/Shared/JsonUtils.cs +++ b/src/SignalR/common/Shared/JsonUtils.cs @@ -143,7 +143,7 @@ public static bool ReadAsBoolean(JsonTextReader reader, string propertyName) return Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture); } - public static string ReadAsString(JsonTextReader reader, string propertyName) + public static string? ReadAsString(JsonTextReader reader, string propertyName) { reader.Read(); diff --git a/src/SignalR/common/SignalR.Common/src/Microsoft.AspNetCore.SignalR.Common.csproj b/src/SignalR/common/SignalR.Common/src/Microsoft.AspNetCore.SignalR.Common.csproj index 1206aeed6833..5aedb5e72287 100644 --- a/src/SignalR/common/SignalR.Common/src/Microsoft.AspNetCore.SignalR.Common.csproj +++ b/src/SignalR/common/SignalR.Common/src/Microsoft.AspNetCore.SignalR.Common.csproj @@ -38,4 +38,8 @@ + + + + diff --git a/src/SignalR/common/SignalR.Common/src/Protocol/HubMethodInvocationMessage.cs b/src/SignalR/common/SignalR.Common/src/Protocol/HubMethodInvocationMessage.cs index cbe3f23ce30d..12dece0f5d9d 100644 --- a/src/SignalR/common/SignalR.Common/src/Protocol/HubMethodInvocationMessage.cs +++ b/src/SignalR/common/SignalR.Common/src/Protocol/HubMethodInvocationMessage.cs @@ -146,7 +146,7 @@ public StreamInvocationMessage(string invocationId, string target, object[] argu /// The target method name. /// The target method arguments. /// The target methods stream IDs. - public StreamInvocationMessage(string invocationId, string target, object[] arguments, string[] streamIds) + public StreamInvocationMessage(string invocationId, string target, object[] arguments, string[]? streamIds) : base(invocationId, target, arguments, streamIds) { } diff --git a/src/SignalR/common/SignalR.Common/src/Protocol/InvocationBindingFailureMessage.cs b/src/SignalR/common/SignalR.Common/src/Protocol/InvocationBindingFailureMessage.cs index 0b866f871e0f..a07a32e9f5af 100644 --- a/src/SignalR/common/SignalR.Common/src/Protocol/InvocationBindingFailureMessage.cs +++ b/src/SignalR/common/SignalR.Common/src/Protocol/InvocationBindingFailureMessage.cs @@ -26,7 +26,7 @@ public class InvocationBindingFailureMessage : HubInvocationMessage /// The invocation ID. /// The target method name. /// The exception thrown during binding. - public InvocationBindingFailureMessage(string invocationId, string target, ExceptionDispatchInfo bindingFailure) : base(invocationId) + public InvocationBindingFailureMessage(string? invocationId, string target, ExceptionDispatchInfo bindingFailure) : base(invocationId) { Target = target; BindingFailure = bindingFailure;