diff --git a/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs b/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs index a361a4ed03..0635cd850a 100644 --- a/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs +++ b/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.SignalR.Client { - public partial class HubConnection + public partial class HubConnection : System.IAsyncDisposable { public static readonly System.TimeSpan DefaultHandshakeTimeout; public static readonly System.TimeSpan DefaultKeepAliveInterval; @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.SignalR.Client public event System.Func Reconnected { add { } remove { } } public event System.Func Reconnecting { add { } remove { } } [System.Diagnostics.DebuggerStepThroughAttribute] - public System.Threading.Tasks.Task DisposeAsync() { throw null; } + public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } [System.Diagnostics.DebuggerStepThroughAttribute] public System.Threading.Tasks.Task InvokeCoreAsync(string methodName, System.Type returnType, object[] args, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public System.IDisposable On(string methodName, System.Type[] parameterTypes, System.Func handler, object state) { throw null; } diff --git a/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.1.cs b/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.1.cs index a361a4ed03..0635cd850a 100644 --- a/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.1.cs +++ b/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.1.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.SignalR.Client { - public partial class HubConnection + public partial class HubConnection : System.IAsyncDisposable { public static readonly System.TimeSpan DefaultHandshakeTimeout; public static readonly System.TimeSpan DefaultKeepAliveInterval; @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.SignalR.Client public event System.Func Reconnected { add { } remove { } } public event System.Func Reconnecting { add { } remove { } } [System.Diagnostics.DebuggerStepThroughAttribute] - public System.Threading.Tasks.Task DisposeAsync() { throw null; } + public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } [System.Diagnostics.DebuggerStepThroughAttribute] public System.Threading.Tasks.Task InvokeCoreAsync(string methodName, System.Type returnType, object[] args, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public System.IDisposable On(string methodName, System.Type[] parameterTypes, System.Func handler, object state) { throw null; } diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs index 5e04bd309a..61a3aceb55 100644 --- a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs +++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs @@ -22,7 +22,6 @@ using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Protocol; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.SignalR.Client { @@ -34,7 +33,7 @@ namespace Microsoft.AspNetCore.SignalR.Client /// Before hub methods can be invoked the connection must be started using . /// Clean up a connection using or . /// - public partial class HubConnection + public partial class HubConnection : IAsyncDisposable { public static readonly TimeSpan DefaultServerTimeout = TimeSpan.FromSeconds(30); // Server ping rate is 15 sec, this is 2 times that. public static readonly TimeSpan DefaultHandshakeTimeout = TimeSpan.FromSeconds(15); @@ -292,8 +291,8 @@ namespace Microsoft.AspNetCore.SignalR.Client /// /// Disposes the . /// - /// A that represents the asynchronous dispose. - public async Task DisposeAsync() + /// A that represents the asynchronous dispose. + public async ValueTask DisposeAsync() { if (!_disposed) { @@ -504,8 +503,16 @@ namespace Microsoft.AspNetCore.SignalR.Client if (disposing) { - (_serviceProvider as IDisposable)?.Dispose(); + // Must set this before calling DisposeAsync because the service provider has a reference to the HubConnection and will try to dispose it again _disposed = true; + if (_serviceProvider is IAsyncDisposable asyncDispose) + { + await asyncDispose.DisposeAsync(); + } + else + { + (_serviceProvider as IDisposable)?.Dispose(); + } } } finally diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.cs index 2c9df93cb8..b303e71ddd 100644 --- a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.cs +++ b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.cs @@ -414,6 +414,17 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests } } + [Fact] + public async Task CanAwaitUsingHubConnection() + { + using (StartVerifiableLog()) + { + var connection = new TestConnection(); + await using var hubConnection = CreateHubConnection(connection, loggerFactory: LoggerFactory); + await hubConnection.StartAsync().OrTimeout(); + } + } + private class SampleObject { public SampleObject(string foo, int bar)