SignalR Broadcast from Controller not working - signalr

I'm using the latest version of SignalR (1.0.1). I am trying to broadcast from my controller to the hub and having a few issues:
My client does not seem to be getting messages.
It doesn't seem that my hub context even has an 'addMessage' defined:
My hub:
public class SignalRPriceHub : Hub
{
public void sndMessage(string msg)
{
Clients.All.addMessage(msg + "****");
}
}
Javascript client:
<script src="#Url.Content("~/Scripts/jquery.signalR-1.0.1.min.js")"></script>
<script src="~/signalr/hubs"></script>
.....
var myHub = $.connection.signalRPriceHub;
myHub.client.addMessage = function (message) {
alert(message);
};
Controller:
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRPriceHub>();
context.Clients.All.addMessage("TestOutsideMessage!!!");
A few things I noticed:
1. My hub context doesn't seem to have an 'addMessage'
{"'Microsoft.AspNet.SignalR.Hubs.ClientProxy' does not contain a definition for 'addMessage'"} System.Exception {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}
If I run the following code from the same file as my client code above, I do get a message.
var myHub = $.connection.signalRPriceHub;
$.connection.hub.start(function () {
myHub.server.sndMessage("Hello World!");
});
Can anyone shed some light as to what might be happening? Thanks all!

I'll go over the faults in your initial application which shed light to why your second bullet point makes it all work.
In your javascript client you must start the connection:
$.connection.hub.start();
You must then request the message on your hub by calling the sndMessage command:
$.connection.hub.start().done(function() {
myHub.server.sndMessage("Hello world");
});
The reason why you do not see an addMessage function on your hub context is because the hub context .Clients.All is dynamic.
One last note, in order to make the sample work you also need to make sure that in your Application_Start you have RouteTable.Routes.MapHubs(); . I assume you already have this since once you add the connection start that everything works.

Related

SignalR - How to call server function with parameter from client using hubproxy

I have my signalr running on a separate domain. We will have multiple applications using it to send and receive messages. I created the connection and hub proxy using the following code
connection = $.hubConnection("https://someurl.com", { useDefaultPath: false });
chatHub = connection.createHubProxy('chatHub');
I can get messages from the server sent to the client using the following code which works fine
chatHub.on('receiveEntityMessage', function (chatMessage) {
if (chatMessage) {
console.log(chatMessage.Message);
}
});
Now I dont know how to call server functions with parameters from the client. Can anybody please help me with this?
chatHub.invoke("MethodName", param1, param2, param3).done(function(result) {
console.log(result);
});
Since i'm not sure what is the language of your server side, i am going to provide a C# example.
C# Hub method example:
public class chatHub: Hub {
public void YourHubMehotd(int firstParam, string secondParam){
//The action of your method
}
}
JS client side:
You can call your hub method like this:
{The variable with the hub connection}.server.{the method you want to call}( {the parameters} )
Example:
chatHub.server.YourHubMehotd(1,"Example");
I recomend to create a js function to call the hub method.
function callMyHubMethod(firstParam, secondParam){
chatHub.server.YourHubMehotd(firstParam, secondParam);
}

SignalR Client method bound before hub.start(), but not being called after Server Method

I can set a breakpoint at my server method and it is being called on hub start. And if i put a breakpoint at hub.start(), I do see that the connection already has the client side version of the method bound. But somehow the method is not being called from server. Here is my code:
Server method
[HubName("MovementHub")]
public class MovementHub : Hub
{
public void UpdatePlayerPosServer(PlayerPosition playerPosition)
{
playerPosition.LastUpdatedBy = Context.ConnectionId;
Clients.AllExcept(playerPosition.LastUpdatedBy).updatePlayerPosClient(playerPosition); //debugging here shows the playerposition all filled out nicely. this hub method is HIT.
}
}
Client Method
$(() => {
var connection = (<any>$.connection).MovementHub;
//this method is never called
connection.client.updatePlayerPosClient = (playerPosModel) => {
alert("updatingremotePlayers: " + playerPosModel);
}
});
Hub Start (typescript class. method is called from another class)
public updateServerPos = (x: number, y: number) => {
var connection = (<any>$.connection).MovementHub;
this.LoginID = $("#displayname").val();
$.connection.hub.start().done(() => {
var playerposModel = { Id: this.LoginID, X: x, Y: y };
connection.server.updatePlayerPosServer(playerposModel); //debugging here shows me that "connection" has the client method bound at this point
}).fail(function(error) {
console.log(error);
});
}
I've read a few posts on this that specify you have to have the client method bound before hub start, but IT IS. And the server method is getting called correctly. So not sure what's goin on here.
Edit: I realized, I'm an idiot and might be falling victim to being skipped by the "AllExcept" call on clients. I was the exception! lol
The only remaining problem onw is why I have to have the client Method "instantiated" in an IFFE? I'd like to put it in the same Typescript class where the server method is being called from.
Turns out MIXING javascript IIFE calls with typescript calls can be hazardous. I have a totally unrelated (i thought) hub start happening BEFORE this client method was bound. I realized, even tho, I have two Hubs, there's really only one hub.start(); silly me.

SignalR Cannot invoke a non-delegate type

I'm trying to learn SignalR by writing a really simple application... it basically sends "Hello" periodically (like the Stock Ticker, but a lot simpler).
Here's my hub:
public class StockTickerHub : Hub
{
public void Hello()
{
var s = StockTicker.stockTicker;
Clients.All.hello();
}
}
...and here's the code that is supposed to periodically send the messages:
public class StockTicker
{
public static StockTicker stockTicker = new StockTicker();
private Thread thread;
public StockTicker()
{
var stockTickerHub = GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>();
this.thread = new Thread(() =>
{
while (true)
{
stockTickerHub.Clients.All().hello();
Thread.Sleep(1000);
}
}
);
this.thread.Start();
}
}
I'm getting a RuntimeBinderException at stockTickerHub.Clients.All().hello();. It says:
An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll
Additional information: Cannot invoke a non-delegate type
What am I doing wrong?
Client-side JavaScript is below, just in case you need to replicate this.
<script type="text/javascript">
$(function () {
var chat = $.connection.stockTickerHub;
chat.client.hello = function () {
$("#log").append("Hello");
}
$.connection.hub.start().done(function () {
chat.server.hello();
});
});
</script>
Simply change:
stockTickerHub.Clients.All().hello();
to:
stockTickerHub.Clients.All.hello();
The debugger should have already tell you this error. I tried your code after the update. It is working.
A remark on the code design:
I wouldn't start a new sending thread in the hello event, that would start one every time this method is invoked by any client. I don't think that's what you want to do. As a smoother example you could start the ticker in Startup class. (If you want a ticker per connection override OnConnected, get the client's connection id and give them separate tickers...)

Uncaught TypeError: Cannot read property 'server' of undefined

I'm trying to leverage SignalR while developing Chrome Extensions. I can run sample successfully but when I try to change the client from webpage to chrome extesion, I got some trouble. I define the connection the same as the sample like below:
var chat = $.connection.myHub;
console.log("start connect");
$.connection.hub.start().done(function () {
// Call the Send method on the hub.
console.log("Test");
//chat.server.send("extension", "start");
chat.server.send("succ");
});
But I always get this error: Uncaught TypeError: Cannot read property 'server' of undefined.
I have already enabled CrossDomain in my server side. Since `chat.server' is invoked, it seems the connection is established successfully. Did I miss adding some files/scripts in my extension folder?
It seems that you are not bringing in the /signalr/hubs file. The auto-generated hubs file is what adds the .server and the .client properties to the connection object. Therefore if you're correctly including the /signalr/hubs file the next step is to ensure that your hub is being included in the dynamically generated JS file.
In my case the problem is that C# automatically change the first letter of Hub name and methods to lower case in hub.js. MyHub1 changes to myHub1 and Hello() changed to hello() in client side automatically.
if you have:
public class MyHub1 : Hub
{
public void Hello()
{
}
}
in your Hub.
in client side it must be used like this:
var simpleHubProxy = $.connection.myHub1;
$.connection.hub.start().done(function () {
console.log("Connected.");
simpleHubProxy.server.hello();
});

SignalR and Hub Persistance

I am trying out SignalR, and i don't quite understand how to call methods from my client in a way that it calls the same hub.
i have two methods in my hub:
private ctlDataManager myManager;
public void StartConnection()
{
myManager = new ctlDataManager("test");
myManager.UpdateItemEvent += myManager_UpdateItemEvent;
myManager.Connect();
}
public void StopConnection()
{
myManager.Disconnect();
}
And in my client i try to call them like this:
var notificationHub = $.connection.notificationHub;
$.connection.hub.start()
.done(function (state) {
$("#submit").click(function (e) {
e.preventDefault();
notificationHub.server.startConnection();
return false;
});
$("#stop").click(function (e) {
e.preventDefault();
notificationHub.server.stopConnection();
return false;
});
});
Now when i click on the start button it works fine it starts it and receives data too.
But when i click the stop button it throws an instance of an object error.
It appears that 'myManager' is null. It's almost as a new hub were open. Naturally i need it to be the same one as i need to close the connection.
How can i do that?
From my understanding, the server-side hub class is not persisted. Therefore, the myManager object is created with each method call from a client. My advice would be to declare myManager elsewhere in your application that you can assure 100% up-time, and have your server-side hub methods communicate with it that way.
One way for you to verify this is to debug the constructor of your hub class. You will notice that it is called for every client->server-side method call.

Resources