parent
3a01d6cff1
commit
8022afd3a2
|
|
@ -24,7 +24,7 @@ namespace ChatSample.Hubs
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task OnDisconnectedAsync()
|
||||
public override Task OnDisconnectedAsync(Exception ex)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace SocketsSample.Hubs
|
|||
await Clients.All.InvokeAsync("Send", $"{Context.Connection.ConnectionId} joined");
|
||||
}
|
||||
|
||||
public override async Task OnDisconnectedAsync()
|
||||
public override async Task OnDisconnectedAsync(Exception ex)
|
||||
{
|
||||
await Clients.All.InvokeAsync("Send", $"{Context.Connection.ConnectionId} left");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export class WebSocketTransport implements ITransport {
|
|||
|
||||
webSocket.onclose = (event: CloseEvent) => {
|
||||
// webSocket will be null if the transport did not start successfully
|
||||
if (thisWebSocketTransport.webSocket && event.wasClean === false) {
|
||||
if (thisWebSocketTransport.webSocket && (event.wasClean === false || event.code !== 1000)) {
|
||||
if (thisWebSocketTransport.onError) {
|
||||
thisWebSocketTransport.onError(event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
|
||||
_reader = ReceiveMessages(_readerCts.Token);
|
||||
_connection.Output.Writing.ContinueWith(
|
||||
t => CompletePendingCalls(t.IsFaulted ? t.Exception : null));
|
||||
t => CompletePendingCalls(t.IsFaulted ? t.Exception.InnerException : null));
|
||||
}
|
||||
|
||||
// TODO: Client return values/tasks?
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task OnDisconnectedAsync()
|
||||
public virtual Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
{
|
||||
// TODO: Dispatch from the caller
|
||||
await Task.Yield();
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
await _lifetimeManager.OnConnectedAsync(connection);
|
||||
|
|
@ -76,6 +76,13 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
|
||||
await DispatchMessagesAsync(connection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(0, ex, "Error when processing requests.");
|
||||
exception = ex;
|
||||
connection.Channel.Input.Complete(exception);
|
||||
connection.Channel.Output.Complete(exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
|
|
@ -83,7 +90,7 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
bool created;
|
||||
var hub = CreateHub(scope.ServiceProvider, connection, out created);
|
||||
|
||||
await hub.OnDisconnectedAsync();
|
||||
await hub.OnDisconnectedAsync(exception);
|
||||
|
||||
if (created)
|
||||
{
|
||||
|
|
@ -232,7 +239,7 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
private static bool IsHubMethod(MethodInfo m)
|
||||
{
|
||||
// TODO: Add more checks
|
||||
return m.IsPublic;
|
||||
return m.IsPublic && !m.IsSpecialName;
|
||||
}
|
||||
|
||||
Type IInvocationBinder.GetReturnType(string invocationId)
|
||||
|
|
@ -243,8 +250,11 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
Type[] IInvocationBinder.GetParameterTypes(string methodName)
|
||||
{
|
||||
Type[] types;
|
||||
// TODO: null or throw?
|
||||
return _paramTypes.TryGetValue(methodName, out types) ? types : null;
|
||||
if (!_paramTypes.TryGetValue(methodName, out types))
|
||||
{
|
||||
throw new InvalidOperationException($"The hub method '{methodName}' could not be resolved.");
|
||||
}
|
||||
return types;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
// Shut down the output pipeline and log
|
||||
_logger.LogError("Error while polling '{0}': {1}", pollUrl, ex);
|
||||
_pipeline.Output.Complete(ex);
|
||||
_pipeline.Input.Complete(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,28 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ServerClosesConnectionIfHubMethodCannotBeResolved()
|
||||
{
|
||||
var loggerFactory = new LoggerFactory();
|
||||
|
||||
using (var httpClient = _testServer.CreateClient())
|
||||
using (var pipelineFactory = new PipelineFactory())
|
||||
{
|
||||
var transport = new LongPollingTransport(httpClient, loggerFactory);
|
||||
using (var connection = await HubConnection.ConnectAsync(new Uri("http://test/hubs"), new JsonNetInvocationAdapter(), transport, httpClient, pipelineFactory, loggerFactory))
|
||||
{
|
||||
//TODO: Get rid of this. This is to prevent "No channel" failures due to sends occuring before the first poll.
|
||||
await Task.Delay(500);
|
||||
|
||||
var ex = await Assert.ThrowsAnyAsync<InvalidOperationException>(
|
||||
async () => await connection.Invoke<Task>("!@#$%"));
|
||||
|
||||
Assert.Equal(ex.Message, "The hub method '!@#$%' could not be resolved.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_testServer.Dispose();
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@
|
|||
using System;
|
||||
using System.IO.Pipelines;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Sockets;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Moq.Protected;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||
|
|
@ -18,7 +21,6 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
{
|
||||
var trackDispose = new TrackDispose();
|
||||
var serviceProvider = CreateServiceProvider(s => s.AddSingleton(trackDispose));
|
||||
|
||||
var endPoint = serviceProvider.GetService<HubEndPoint<TestHub>>();
|
||||
|
||||
using (var connectionWrapper = new ConnectionWrapper())
|
||||
|
|
@ -36,6 +38,44 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OnDisconnectedCalledWithExceptionIfHubMethodNotFound()
|
||||
{
|
||||
var hub = Mock.Of<Hub>();
|
||||
|
||||
var endPointType = GetEndPointType(hub.GetType());
|
||||
var serviceProvider = CreateServiceProvider(s =>
|
||||
{
|
||||
s.AddSingleton(endPointType);
|
||||
s.AddTransient(hub.GetType(), sp => hub);
|
||||
});
|
||||
|
||||
dynamic endPoint = serviceProvider.GetService(endPointType);
|
||||
|
||||
using (var connectionWrapper = new ConnectionWrapper())
|
||||
{
|
||||
var endPointTask = endPoint.OnConnectedAsync(connectionWrapper.Connection);
|
||||
|
||||
await connectionWrapper.HttpConnection.Input.ReadingStarted;
|
||||
|
||||
var buffer = connectionWrapper.HttpConnection.Input.Alloc();
|
||||
buffer.Write(Encoding.UTF8.GetBytes("0xdeadbeef"));
|
||||
await buffer.FlushAsync();
|
||||
|
||||
connectionWrapper.Connection.Channel.Dispose();
|
||||
|
||||
await endPointTask;
|
||||
|
||||
Mock.Get(hub).Verify(h => h.OnDisconnectedAsync(It.IsNotNull<Exception>()), Times.Once());
|
||||
}
|
||||
}
|
||||
|
||||
private static Type GetEndPointType(Type hubType)
|
||||
{
|
||||
var endPointType = typeof(HubEndPoint<>);
|
||||
return endPointType.MakeGenericType(hubType);
|
||||
}
|
||||
|
||||
private class TestHub : Hub
|
||||
{
|
||||
private TrackDispose _trackDispose;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"Microsoft.AspNetCore.SignalR": "1.0.0-*",
|
||||
"Microsoft.Extensions.DependencyInjection": "1.2.0-*",
|
||||
"Microsoft.Extensions.Logging": "1.2.0-*",
|
||||
"Moq": "4.6.36-*",
|
||||
"xunit": "2.2.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue