Handling exceptions thrown when invoking a hub method (#332)
This commit is contained in:
parent
5642f09a83
commit
e955c4b9aa
|
|
@ -102,8 +102,6 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
public Task<object> Invoke(string methodName, Type returnType, params object[] args) => Invoke(methodName, returnType, CancellationToken.None, args);
|
||||
public async Task<object> Invoke(string methodName, Type returnType, CancellationToken cancellationToken, params object[] args)
|
||||
{
|
||||
// TODO: we should reject calls to here after the connection is "done" or has not been started (e.g. sending an invocation failed)
|
||||
|
||||
_logger.LogTrace("Preparing invocation of '{0}', with return type '{1}' and {2} args", methodName, returnType.AssemblyQualifiedName, args.Length);
|
||||
|
||||
// Create an invocation descriptor.
|
||||
|
|
@ -134,15 +132,26 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
_logger.LogTrace("Invocation #{0}: {1} {2}({3})", descriptor.Id, returnType.FullName, methodName, argsList);
|
||||
}
|
||||
|
||||
var ms = new MemoryStream();
|
||||
await _adapter.WriteMessageAsync(descriptor, ms, cancellationToken);
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
await _adapter.WriteMessageAsync(descriptor, ms, cancellationToken);
|
||||
|
||||
_logger.LogInformation("Sending Invocation #{0}", descriptor.Id);
|
||||
_logger.LogInformation("Sending Invocation #{0}", descriptor.Id);
|
||||
|
||||
// TODO: Format.Text - who, where and when decides about the format of outgoing messages
|
||||
// TODO HIGH: Handle return value/Exception from SendAsync
|
||||
await _connection.SendAsync(ms.ToArray(), MessageType.Text, cancellationToken);
|
||||
_logger.LogInformation("Sending Invocation #{0} complete", descriptor.Id);
|
||||
// TODO: Format.Text - who, where and when decides about the format of outgoing messages
|
||||
await _connection.SendAsync(ms.ToArray(), MessageType.Text, cancellationToken);
|
||||
_logger.LogInformation("Sending Invocation #{0} complete", descriptor.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(0, ex, "Sending Invocation #{0} failed", descriptor.Id);
|
||||
irq.Completion.TrySetException(ex);
|
||||
lock (_pendingCallsLock)
|
||||
{
|
||||
_pendingCalls.Remove(descriptor.Id);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the completion task. It will be completed by ReceiveMessages when the response is received.
|
||||
return await irq.Completion.Task;
|
||||
|
|
@ -294,7 +303,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
|
||||
public InvocationRequest(CancellationToken cancellationToken, Type resultType)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
Completion = tcs;
|
||||
CancellationToken = cancellationToken;
|
||||
Registration = cancellationToken.Register(() => tcs.TrySetCanceled());
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging;
|
|||
using Moq;
|
||||
using Moq.Protected;
|
||||
using Xunit;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||
{
|
||||
|
|
@ -92,24 +93,43 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact(Skip = "Not implemented")]
|
||||
[Fact]
|
||||
public async Task InvokeThrowsIfHubConnectionNotStarted()
|
||||
{
|
||||
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"), Mock.Of<IInvocationAdapter>(), Mock.Of<ILoggerFactory>());
|
||||
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"));
|
||||
var exception =
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await hubConnection.Invoke<int>("test"));
|
||||
Assert.Equal("Cannot invoke methods on non-started connections.", exception.Message);
|
||||
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Not implemented")]
|
||||
[Fact]
|
||||
public async Task InvokeThrowsIfHubConnectionDisposed()
|
||||
{
|
||||
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"), Mock.Of<IInvocationAdapter>(), Mock.Of<ILoggerFactory>());
|
||||
var hubConnection = new HubConnection(new Uri("http://fakeuri.org"));
|
||||
await hubConnection.DisposeAsync();
|
||||
|
||||
var exception =
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await hubConnection.Invoke<int>("test"));
|
||||
Assert.Equal("Cannot invoke methods on disposed connections.", exception.Message);
|
||||
Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeThrowsIfSerializingMessageFails()
|
||||
{
|
||||
var mockConnection = new Mock<IConnection>();
|
||||
|
||||
var exception = new InvalidOperationException();
|
||||
var mockInvocationAdapter = new Mock<IInvocationAdapter>();
|
||||
mockInvocationAdapter
|
||||
.Setup(a => a.WriteMessageAsync(It.IsAny<InvocationMessage>(), It.IsAny<Stream>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromException(exception));
|
||||
|
||||
var hubConnection = new HubConnection(mockConnection.Object, mockInvocationAdapter.Object, null);
|
||||
await hubConnection.StartAsync(Mock.Of<ITransport>());
|
||||
|
||||
var actualException =
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await hubConnection.Invoke<int>("test"));
|
||||
Assert.Same(exception, actualException);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue