Pass serialization exceptions to Hub disconnect (#24408)

This commit is contained in:
Brennan 2020-07-31 10:13:28 -07:00 committed by GitHub
parent f28ef7c3e8
commit 4290bcc782
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 13 deletions

View File

@ -91,6 +91,8 @@ namespace Microsoft.AspNetCore.SignalR
internal HubCallerContext HubCallerContext { get; } internal HubCallerContext HubCallerContext { get; }
internal Exception CloseException { get; private set; }
/// <summary> /// <summary>
/// Gets a <see cref="CancellationToken"/> that notifies when the connection is aborted. /// Gets a <see cref="CancellationToken"/> that notifies when the connection is aborted.
/// </summary> /// </summary>
@ -212,6 +214,7 @@ namespace Microsoft.AspNetCore.SignalR
} }
catch (Exception ex) catch (Exception ex)
{ {
CloseException = ex;
Log.FailedWritingMessage(_logger, ex); Log.FailedWritingMessage(_logger, ex);
AbortAllowReconnect(); AbortAllowReconnect();
@ -231,6 +234,7 @@ namespace Microsoft.AspNetCore.SignalR
} }
catch (Exception ex) catch (Exception ex)
{ {
CloseException = ex;
Log.FailedWritingMessage(_logger, ex); Log.FailedWritingMessage(_logger, ex);
AbortAllowReconnect(); AbortAllowReconnect();
@ -247,6 +251,7 @@ namespace Microsoft.AspNetCore.SignalR
} }
catch (Exception ex) catch (Exception ex)
{ {
CloseException = ex;
Log.FailedWritingMessage(_logger, ex); Log.FailedWritingMessage(_logger, ex);
AbortAllowReconnect(); AbortAllowReconnect();
@ -274,6 +279,7 @@ namespace Microsoft.AspNetCore.SignalR
} }
catch (Exception ex) catch (Exception ex)
{ {
CloseException = ex;
Log.FailedWritingMessage(_logger, ex); Log.FailedWritingMessage(_logger, ex);
AbortAllowReconnect(); AbortAllowReconnect();
} }
@ -299,6 +305,7 @@ namespace Microsoft.AspNetCore.SignalR
} }
catch (Exception ex) catch (Exception ex)
{ {
CloseException = ex;
Log.FailedWritingMessage(_logger, ex); Log.FailedWritingMessage(_logger, ex);
AbortAllowReconnect(); AbortAllowReconnect();
} }
@ -336,6 +343,7 @@ namespace Microsoft.AspNetCore.SignalR
} }
catch (Exception ex) catch (Exception ex)
{ {
CloseException = ex;
Log.FailedWritingMessage(_logger, ex); Log.FailedWritingMessage(_logger, ex);
AbortAllowReconnect(); AbortAllowReconnect();
} }

View File

@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.SignalR
return; return;
} }
await HubOnDisconnectedAsync(connection, null); await HubOnDisconnectedAsync(connection, connection.CloseException);
} }
private async Task HubOnDisconnectedAsync(HubConnectionContext connection, Exception exception) private async Task HubOnDisconnectedAsync(HubConnectionContext connection, Exception exception)

View File

@ -189,16 +189,6 @@ namespace Microsoft.AspNetCore.SignalR.Tests
{ {
} }
private class SelfRef
{
public SelfRef()
{
Self = this;
}
public SelfRef Self { get; set; }
}
public async Task<string> StreamingConcat(ChannelReader<string> source) public async Task<string> StreamingConcat(ChannelReader<string> source)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -331,6 +321,16 @@ namespace Microsoft.AspNetCore.SignalR.Tests
} }
} }
internal class SelfRef
{
public SelfRef()
{
Self = this;
}
public SelfRef Self { get; set; }
}
public abstract class TestHub : Hub public abstract class TestHub : Hub
{ {
public override Task OnConnectedAsync() public override Task OnConnectedAsync()
@ -1123,9 +1123,20 @@ namespace Microsoft.AspNetCore.SignalR.Tests
return base.OnConnectedAsync(); return base.OnConnectedAsync();
} }
public Task ProtocolErrorSelf()
{
return Clients.Caller.SendAsync("Send", new SelfRef());
}
public Task ProtocolErrorAll()
{
return Clients.All.SendAsync("Send", new SelfRef());
}
public override Task OnDisconnectedAsync(Exception exception) public override Task OnDisconnectedAsync(Exception exception)
{ {
_state.TokenStateInDisconnected = Context.ConnectionAborted.IsCancellationRequested; _state.TokenStateInDisconnected = Context.ConnectionAborted.IsCancellationRequested;
_state.DisconnectedException = exception;
return base.OnDisconnectedAsync(exception); return base.OnDisconnectedAsync(exception);
} }
@ -1138,6 +1149,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public bool TokenStateInConnected { get; set; } public bool TokenStateInConnected { get; set; }
public bool TokenStateInDisconnected { get; set; } public bool TokenStateInDisconnected { get; set; }
public Exception DisconnectedException { get; set; }
} }
public class CallerServiceHub : Hub public class CallerServiceHub : Hub

View File

@ -19,10 +19,8 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections.Features; using Microsoft.AspNetCore.Http.Connections.Features;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Protocol; using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
@ -3342,6 +3340,52 @@ namespace Microsoft.AspNetCore.SignalR.Tests
} }
} }
[Fact]
public async Task SerializationExceptionsSendSelfArePassedToOnDisconnectedAsync()
{
using (StartVerifiableLog(write => write.EventId.Name == "FailedWritingMessage"))
{
var state = new ConnectionLifetimeState();
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(s => s.AddSingleton(state), LoggerFactory);
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ConnectionLifetimeHub>>();
using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler);
// Test HubConnectionContext.WriteCore(HubMessage) codepath
await client.SendInvocationAsync(nameof(ConnectionLifetimeHub.ProtocolErrorSelf)).OrTimeout();
await connectionHandlerTask.OrTimeout();
Assert.IsType<System.Text.Json.JsonException>(state.DisconnectedException);
}
}
}
[Fact]
public async Task SerializationExceptionsSendAllArePassedToOnDisconnectedAsync()
{
using (StartVerifiableLog(write => write.EventId.Name == "FailedWritingMessage"))
{
var state = new ConnectionLifetimeState();
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(s => s.AddSingleton(state), LoggerFactory);
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ConnectionLifetimeHub>>();
using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler);
// Test HubConnectionContext.WriteCore(SerializedHubMessage) codepath
await client.SendInvocationAsync(nameof(ConnectionLifetimeHub.ProtocolErrorAll)).OrTimeout();
await connectionHandlerTask.OrTimeout();
Assert.IsType<System.Text.Json.JsonException>(state.DisconnectedException);
}
}
}
[Fact(Skip = "Magic auto cast not supported")] [Fact(Skip = "Magic auto cast not supported")]
public async Task UploadStreamItemInvalidTypeAutoCasts() public async Task UploadStreamItemInvalidTypeAutoCasts()
{ {