Question

I am trying to set SignalR up, but I keep getting the following error when adding a message:

"Cannot perform runtime binding on a null reference"

My ClientSide code looks like this:

commentHub.addMessage = function (message) {
    $('#divMessages').append(message);
};

And my serverside code looks like this:

public void Send(string message)
{
     Clients.addMessage(message);
}

I first open one window where the client side code is at, and then I open a new page which invokes the Send method from codebehind. To test it out, I simply invoke the send Method like this:

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);
    new TestHub().Send("Test");
}

I first thought that the error came from a call in the wrong place in the page cycle, so I moved it from OnInit to PreRender, but I stil receive the error. Now I am wondering if I have to execute the Send command from Client side to get it updated?

Was it helpful?

Solution

If I understand correctly you want to invoke the client method from the server. The issue is that the server is a hub which is basically just a service. You could try to do as @sinanakyazici suggests however this is not a typical interaction.

If your goal is to notify connected clients of some server event then you can follow the doc here (https://github.com/SignalR/SignalR/wiki/Hubs), in the last section called "Broadcasting over a Hub from outside of a Hub". Please note that during the page lifecycle, the user is NOT connected to the hub as the page is refreshing. It is only after the page loads and the javascript $.connection.start() method is invoked that the user is connected. Even if you were to send a message through the hub, the user who caused the page refresh will not receive that message. That said there are times when you want to send a message from code behind to other users, that can be accomplished as mentioned by following the wiki and looks like:

using SignalR.Infrastructure;

IConnectionManager connectionManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
dynamic clients = connectionManager.GetClients<MyHub>();
// invoke javascript method for all connected clients
clients.addMessage("Your message here");

For your specific requirement it sounds like you want the caller to get feedback as to the status of some long running task. This is where you would typically invoke the hub from the client side and the hub would then report back progress reports until complete at which point it could fire a completed callback. Typically this is done using the following:

public void SomeTask(string message)
{
     dowork();
     // send message only to the invoker
     Caller.addMessage("50% complete");
     domorework();
     // send message only to the invoker
     Caller.addMessage("100% complete");
     // fire processComplete javascript function
     Caller.processComplete();
}

OTHER TIPS

You should install Newtonsoft.Json from Nuget. Then,

    protected void Button_OnClick(object sender, EventArgs e)
    {
        //{0} = your hub class name with namespace. Example: SignalR.TestHub
        //{1} = your host address. Example : http://localhost:1234 
        HubConnection hubConnection = new HubConnection("{1}");
        IHubProxy hub= hubConnection.CreateProxy("{0}");
        hubConnection.Start().Wait();
        hub.Invoke("Send","message");
    }

You can do this way.

The thing is I'm pretty sure SignalR needs to be started, so creating the hub instance yourself would be missing a lot of intialization code that would be normaly done (like binding the Clients dynamic object, etc.) Either find a way to do what is done in the $.connection.start on the client start, or I would call this from the client side:

Client.js

$.connection.start(function() {
  $.connection.testHub.Send("test");
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top