Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR server --> client call not working

I'm currently using SignalR to communicate between a server and multiple separate processes spawned by the server itself. Both Server & Client are coded in C#. I'm using SignalR 2.2.0.0 On the server side, I use OWIN to run the server. I am also using LightInject as an IoC container.

Here is my code:

public class AgentManagementStartup
{
    public void ConfigurationOwin(IAppBuilder app, IAgentManagerDataStore dataStore)
    {
        var serializer = new JsonSerializer
        {
            PreserveReferencesHandling = PreserveReferencesHandling.Objects,
            TypeNameHandling = TypeNameHandling.Auto,
            TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
        };

        var container = new ServiceContainer();
        container.RegisterInstance(dataStore);
        container.RegisterInstance(serializer);
        container.Register<EventHub>();
        container.Register<ManagementHub>();
        var config = container.EnableSignalR();

        app.MapSignalR("", config);
    }
}

On the client side, I register this way:

public async Task Connect()
{
    try
    {
        m_hubConnection = new HubConnection(m_serverUrl, false);
        m_hubConnection.Closed += OnConnectionClosed;
        m_hubConnection.TraceLevel = TraceLevels.All;
        m_hubConnection.TraceWriter = Console.Out;

        var serializer = m_hubConnection.JsonSerializer;
        serializer.TypeNameHandling = TypeNameHandling.Auto;
        serializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects;

        m_managementHubProxy = m_hubConnection.CreateHubProxy(AgentConstants.ManagementHub.Name);
        m_managementHubProxy.On("closeRequested", CloseRequestedCallback);

        await m_hubConnection.Start();
    }
    catch (Exception e)
    {
        m_logger.Error("Exception encountered in Connect method", e);
    }
}

On the server side I send a close request the following way:

var managementHub = GlobalHost.ConnectionManager.GetHubContext<ManagementHub>();
managementHub.Clients.All.closeRequested();

I never receive any callback in CloseRequestedCallback. Neither on the Client side nor on the server side I get any errors in the logs.

What did I do wrong here ?

EDIT 09/10/15

After some research and modifications, I found out it was linked with the replacement of the IoC container. When I removed everything linked to LightInject and used SignalR as is, everything worked. I was surprised about this since LightInject documented their integration with SignalR.

After I found this, I realised that the GlobalHost.DependencyResolver was not the same as the one I was supplying to the HubConfiguration. Once I added

GlobalHost.DependencyResolver = config.Resolver;

before

app.MapSignalR("", config);

I am now receiving callbacks within CloseRequestedCallback. Unfortunately, I get the following error as soon as I call a method from the Client to the Server:

Microsoft.AspNet.SignalR.Client.Infrastructure.SlowCallbackException

Possible deadlock detected. A callback registered with "HubProxy.On" or "Connection.Received" has been executing for at least 10 seconds.

I am not sure about the fix I found and what impact it could have on the system. Is it OK to replace the GlobalHost.DependencyResolver with my own without registering all of its default content ?

EDIT 2 09/10/15

According to this, changing the GlobalHost.DependencyResolver is the right thing to do. Still left with no explanation for the SlowCallbackException since I do nothing in all my callbacks (yet).

like image 864
Joel Bourbonnais Avatar asked Sep 09 '15 20:09

Joel Bourbonnais


People also ask

Is SignalR bidirectional?

ASP.NET SignalR is a new library for ASP.NET developers that makes developing real-time web functionality easy. SignalR allows bi-directional communication between server and client.

How many clients can SignalR handle?

IIS on client operating systems has a limit of 10 concurrent connections. SignalR's connections are: Transient and frequently re-established. Not disposed immediately when no longer used.

How do I send client specific messages using SignalR?

We change the BroadcastChartData() method to accept connectionId as an additional parameter. This way, we can find the client using the connectionId and send a message just to that client. Additionally, we add a new GetConnectionId() method, which returns the connectionId of the client.


1 Answers

Issue 1: IoC Container + Dependency Injection

If you want to change the IoC for you HubConfiguration, you also need to change the one from the GlobalHost so that returns the same hub when requesting it ouside of context.

Issue 2: Unexpected SlowCallbackException

This exception was caused by the fact that I was using SignalR within a Console Application. The entry point of the app cannot be an async method so to be able to call my initial configuration asynchronously I did as follow:

private static int Main()
{
    var t = InitAsync();
    t.Wait();
    return t.Result;
}

Unfortunately for me, this causes a lot of issues as described here & more in details here.

By starting my InitAsync as follow:

private static int Main()
{
    Task.Factory.StartNew(async ()=> await InitAsync());
    m_waitInitCompletedRequest.WaitOne(TimeSpan.FromSeconds(30));
    return (int)EndpointErrorCode.Ended;
}

Everything now runs fine and I don't get any deadlocks.

For more details on the issues & answers, you may also refer to the edits in my question.

like image 56
Joel Bourbonnais Avatar answered Sep 21 '22 15:09

Joel Bourbonnais