fix #1199 by suppressing ODE in received callback (#1395)

This commit is contained in:
Andrew Stanton-Nurse 2018-02-01 15:08:52 -08:00 committed by GitHub
parent f58ea8133b
commit b61dc35ee6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 9 deletions

View File

@ -97,7 +97,18 @@ namespace Microsoft.AspNetCore.SignalR.Client
if (_needKeepAlive)
{
_logger.ResettingKeepAliveTimer();
_timeoutTimer.Change(ServerTimeout, Timeout.InfiniteTimeSpan);
// If the connection is disposed while this callback is firing, or if the callback is fired after dispose
// (which can happen because of some races), this will throw ObjectDisposedException. That's OK, because
// we don't need the timer anyway.
try
{
_timeoutTimer.Change(ServerTimeout, Timeout.InfiniteTimeSpan);
}
catch (ObjectDisposedException)
{
// This is OK!
}
}
}
@ -157,8 +168,10 @@ namespace Microsoft.AspNetCore.SignalR.Client
private async Task DisposeAsyncCore()
{
_timeoutTimer.Dispose();
await _connection.DisposeAsync();
// Dispose the timer AFTER shutting down the connection.
_timeoutTimer.Dispose();
}
// TODO: Client return values/tasks?

View File

@ -207,6 +207,21 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
Assert.Equal("Server timeout (100.00ms) elapsed without receiving a message from the server.", exception.Message);
}
[Fact]
public async Task OnReceivedAfterTimerDisposedDoesNotThrow()
{
var connection = new TestConnection();
var hubConnection = new HubConnection(connection, new JsonHubProtocol(), new LoggerFactory());
await hubConnection.StartAsync().OrTimeout();
await hubConnection.DisposeAsync().OrTimeout();
// Fire callbacks, they shouldn't fail
foreach (var registration in connection.Callbacks)
{
await registration.InvokeAsync(new byte[0]);
}
}
// Moq really doesn't handle out parameters well, so to make these tests work I added a manual mock -anurse
private class MockHubProtocol : IHubProtocol
{

View File

@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
private bool _closed;
private object _closedLock = new object();
private readonly List<ReceiveCallback> _callbacks = new List<ReceiveCallback>();
public List<ReceiveCallback> Callbacks { get; } = new List<ReceiveCallback>();
public IFeatureCollection Features { get; } = new FeatureCollection();
@ -130,9 +130,9 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
while (_receivedMessages.Reader.TryRead(out var message))
{
ReceiveCallback[] callbackCopies;
lock (_callbacks)
lock (Callbacks)
{
callbackCopies = _callbacks.ToArray();
callbackCopies = Callbacks.ToArray();
}
foreach (var callback in callbackCopies)
@ -170,14 +170,14 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
public IDisposable OnReceived(Func<byte[], object, Task> callback, object state)
{
var receiveCallBack = new ReceiveCallback(callback, state);
lock (_callbacks)
lock (Callbacks)
{
_callbacks.Add(receiveCallBack);
Callbacks.Add(receiveCallBack);
}
return new Subscription(receiveCallBack, _callbacks);
return new Subscription(receiveCallBack, Callbacks);
}
private class ReceiveCallback
public class ReceiveCallback
{
private readonly Func<byte[], object, Task> _callback;
private readonly object _state;