signalR - how to call server method from client - code not working - asp.net

When I try calling SendNewOrderConfirmation on the server side from the client I get
"undefined" is not a function
on line chat.SendNewOrderConfirmation(data);
does anyone know why is this happening?
Thank you
on the server side
public class DriverChat : Hub, IDisconnect
{
public void Start(Driver d)
{
...
}
public void SendNewOrderConfirmation(OrderDriverData data)
{
LogFile.LogResponseTime(data.orderId, data.driverId);
}
}
on the client side
function begin(args) {
try {
//alert('begin');
chat = $.connection.driverChat;
chat.refresh = function () {
ready++;
};
chat.disconnect = function () {
alert('Server has disconnected');
};
$.connection.hub.start(function () {
chat.start(args);
ready++;
// alert('signalR started');
});
} catch (e) {
alert(e.message);
return e.message;
}
}
function confirmNewOrder(data) {
try{
alert('sending cofirmation');
chat.SendNewOrderConfirmation(data);
alert('confirmation sent');
} catch (e) {
alert(e);
}
};
}

Depending on the version of SignalR which you are using, the answer could be different.
To begin with, if you are on a version prior to v1 Alpha, then your code should be;
chat.sendNewOrderConfirmation(data);
Notice the lowercase s.
If you are on version v1 Alpha or greater, then you code should be;
chat.server.sendNewOrderConfirmation(data);

You have to register the hub's javascript generated file. Add this to your page (or your master page):
<script src="<%: ResolveUrl("~/signalr/hubs") %>"></script>

Related

SignalR in the loop

I am using SignalR in loop like this:
int itemsCount = 100;
for (int i = 0; i <= itemsCount; i++)
{
Thread.Sleep(100);
SummaryHub.SendMessages("test", i.ToString());
}
and client site is:
$(function () {
var notifications = $.connection.SummaryHub;
// Create a function that the hub can call to broadcast messages.
notifications.client.broadcastMessage = function (name, message) {
console.log(name);
console.log(message);
};
// Start the connection.
$.connection.hub.start().done(function () {
// $.connection.hub.start({ waitForPageLoad: false }).done(function () {
console.log("connection started")
}).fail(function (e) {
alert(e);
});
});
[HubName("SummaryHub")]
public class SummaryHub : Hub
{
[HubMethodName("sendMessages")]
public static void SendMessages(string name, string message)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<SummaryHub>();
context.Clients.All.broadcastMessage(name, message);
}
}
Problem is that client receive messages after loop is done, not during the loop. How can I fix that? Thanks
I find out. It was ajax call with async:false and that was preventing sending messages to the client. Change async to true solved the problem

How to properly configure Stomp and SockJS endpoint in Spring MVC?

This is/may be duplicate of:
Websocket - InvalidStateError: The connection has not been established yet.
I am implementing Notification System. And want to initialize Socket connection when user Logged In, and show him his notifications, and also if some event happens.
My Code snippet as follows.
websocket.js :
var stompClient = null;
function connect( temp ) {
alert(temp);
//var socket = new SockJS("/websock");
//var socket = new SockJS("/websock"+temp);
var socket = new SockJS(context_path+"/websock"+temp);
//context_path == "/SupportCenter"
stompClient = Stomp.over(socket);
stompClient.connect({}, function( frame ){
console.log( "Connected :- "+frame );
stompClient.subscribe("/topic/notifications", function( notifications ) {
alert( notifications );
});
}, function( error ) {
alert( error );
});
alert();
getNotifications();
}
function getNotifications() {
stompClient.send("/app/hello", {}, "Hiiiiii");
}
WebSocketConfig.java :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
/* (non-Javadoc)
* #see org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer#registerStompEndpoints(org.springframework.web.socket.config.annotation.StompEndpointRegistry)
*/
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/websock").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// TODO Auto-generated method stub
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
}
WebSocketController.java :
#Controller
public class WebSocketController {
#MessageMapping(value="/hello")
#SendTo("/topic/notifications")
public Notify hello() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Notify notify = new Notify();
notify.setMessage("Hello World !!!");
return notify;
}
}
Some code Hom.jsp :
<script type="text/javascript" src="<c:url value="/resources/js/sockjs.min.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/js/stomp.min.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/js/websocket.js"/>"></script>
<script type="text/javascript">
$(document).ready(function() {
//...
connect( '${nsec}');
});
Why Firefox Console giving XML Parsing Error: no root element found Location: while in Network tab status code is 200 OK.
Console Tab
Network Tab
Originaly posted to this question.
This is because stompClient.connect() method is asynchronous. I doesn't pause the execution waiting until connection is established. When you call getNotifications() right after alert() most probably connection is not established yet (it might be established if alert() takes enough time to connect).
You are supposed to call getNotifications() in stompClient.connect() callback (just like you do with stompClient.subscribe()) to be sure that connection is established by the time it gets invoked.
For example:
stompClient.connect({}, function( frame ){
console.log( "Connected :- "+frame );
stompClient.subscribe("/topic/notifications", function( notifications ) {
alert( notifications );
});
getNotifications();
}, function( error ) {
alert( error );
});
Besides of that you may consider using #SubscribeMapping annotation in your java code to get rid of explicit message from JavaScript to get initial message from the server. This way the server sends initial message as soon as subscription is established.
For example:
#MessageMapping(value="/hello")
#SubscribeMapping("/notifications")
#SendTo("/topic/notifications")
public Notify hello() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Notify notify = new Notify();
notify.setMessage("Hello World !!!");
return notify;
}
Then client code would look like following:
stompClient.connect({}, function( frame ){
console.log( "Connected :- "+frame );
stompClient.subscribe("/topic/notifications", function( notifications ) {
alert( notifications );
});
}, function( error ) {
alert( error );
});

Return count of connected clients in SignalR. Not firing client function

I am trying to return the count of all connections to a web client with SignalR. I increment and persist the client count by firing logic on the hub OnConnected() method.
public class PopHub : Hub
{
public static List<string> Users = new List<string>();
public override Task OnConnected()
{
var clientId = GetClientId();
if (Users.IndexOf(clientId) == -1)
{
Users.Add(clientId);
}
Send(Users.Count);
return base.OnConnected();
}
public void Send(int count)
{
Clients.All.updateUsersOnlineCount(count);
}
stepping through my code with an external console client (to trigger OnConnected()) shows that I am traversing through Send(int count) with a count of 1.
On my web client, I configure my JS as such
$(function() {
var hub = $.connection.popHub;
hub.client.updateUsersOnlineCount = function(count) {
console.log(count);
};
$.connection.hub.start().done(function() {
console.log('connected');
});
}());
And lastly my snippet from the generated js
proxies.popHub = this.createHubProxy('popHub');
proxies.popHub.client = { };
proxies.popHub.server = {
popClient: function (message) {
return proxies.popHub.invoke.apply(proxies.popHub, $.merge(["PopClient"], $.makeArray(arguments)));
},
query: function () {
return proxies.popHub.invoke.apply(proxies.popHub, $.merge(["Query"], $.makeArray(arguments)));
},
send: function (count) {
return proxies.popHub.invoke.apply(proxies.popHub, $.merge(["Send"], $.makeArray(arguments)));
}
};
**Note that Popclient and Query are unrelated server side events, of which do work giving me somewhat of a sanity check. Any idea why my clients updateUsersOnlineCount function is not logging the count of connections as I expect?
Instead of doing it in the OnConnected, please give this a try, it might be that the Base.OnConnected has not been executed yet, so it's not ready to broadcast to clients.
//Client
$.connection.hub.start().done(function() {
console.log('connected');
hub.server.ClientCount();
});
//Hub
public static List<string> Users = new List<string>();
public override Task OnConnected()
{
var clientId = GetClientId();
if (Users.IndexOf(clientId) == -1)
{
Users.Add(clientId);
}
//Send(Users.Count); //not calling this since it's not working
return base.OnConnected();
}
public void ClientCount()
{
Clients.All.updateUsersOnlineCount(Users.Count);
}

SignalR - Javascript Hub Proxies

When you use SignalR, in your HTML you need to reference the following two scripts:
<script src="~/Scripts/jquery.signalR-1.0.0.js"></script>
<script src="/signalR/hubs"></script>
The second one is for a JavaScript hub proxy which will be auto generated. Everything works fine. However what happens if the JavaScript Hub Proxy generation is disabled somehow, perhaps by setting DisableJavaScriptProxies property (https://github.com/SignalR/SignalR/commit/7e974f4e92551a26f3e3e0a166e1dbf6c064e850). When JavaScript proxy generation is disabled and you try to reference /signalr/hubs in your HTML, it gives the JavaScript error:
Uncaught Error: SignalR: JavaScript Hub proxy generation has been disabled.
When I browse to that path in the browser, the response is:
throw new Error('SignalR: JavaScript Hub proxy generation has been disabled.')
If the JavaScript proxy generation is disabled, how is the $.connection.myHub.client JavaScript code going to work? What extra do I have to do to make it work? The JavaScript error I get is
Uncaught TypeError: cannot read property 'client' of undefined.
You can create the proxies yourself. See here.
This is also done in the samples project within the SignalR source. See the MouseTracking example. JS for it (from here):
/// <reference path="../../Scripts/jquery-1.8.2.js" />
/// <reference path="../../Scripts/jquery.signalR.js" />
$(function () {
var hubConnection = $.hubConnection('/signalr', { qs: 'test=1', logging: false, useDefaultPath: false }),
hub = hubConnection.createHubProxy('mouseTracking');
hub.on('move', updateCursor);
function updateCursor(id, x, y) {
var e = document.getElementById(id);
if (!e) {
e = $('<div id="' + id + '"><i class="icon-screenshot"></i>' + id + '</div>').appendTo(document.body);
e.css('position', 'absolute');
}
else {
e = $(e);
}
e.css({ left: x + 15, top: y + 15 });
}
hubConnection.logging = true;
hubConnection.start({ transport: activeTransport })
.pipe(function () {
return hub.invoke('join');
})
.pipe(function () {
$(document).mousemove(function (e) {
hub.invoke('move', e.pageX, e.pageY);
updateCursor(hub.state.id, e.pageX, e.pageY);
});
});
});
You may have disabled it in your Startup class, like so:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR("/signalr", hubConfiguration);
}
}
I had the code above. Removing/commenting out this line: hubConfiguration.EnableJavaScriptProxies = false; should give you proxy generation.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
app.MapSignalR("/signalr", hubConfiguration);
}
}
For everybody who stumbles on this issue. It seems to be by design, and even the SignalR utility generates only server proxy methods.
It will not create client methods, even if you have a strongly typed Hub (Client interface).
So, the only correct answer, should be that you should generate small functions, as documented at Microsoft.
As in the stockticker sample:
$.connection.hub.start()
.then(init)
.then(function () {
return ticker.server.getMarketState();
})
.done(function (state) {
if (state === 'Open') {
ticker.client.marketOpened();
} else {
ticker.client.marketClosed();
}
The stockticker itself is defined like this
public class StockTickerHub : Hub
and the interface
public interface IClientStock
{
void MarketOpened();
void MarketClosed();
void MarketReset();
void UpdateStockPrice(Stock stock);
}
So for each client proxy method, repeat this. This should not break any bodies project targets.
$.extend(ticker.client, {
updateStockPrice: function (stock) {
var displayStock = formatStock(stock),
$row = $(rowTemplate.supplant(displayStock)),
$li = $(liTemplate.supplant(displayStock)),
bg = stock.LastChange < 0
? '255,148,148' // red
: '154,240,117'; // green
$stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
.replaceWith($row);
$stockTickerUl.find('li[data-symbol=' + stock.Symbol + ']')
.replaceWith($li);
$row.flash(bg, 1000);
$li.flash(bg, 1000);
},
marketOpened: function () {
$("#open").prop("disabled", true);
$("#close").prop("disabled", false);
$("#reset").prop("disabled", true);
scrollTicker();
},

Signalr Owin simple example javascript client not being called

I have a 5.3.0 version of signalr self hosting that is being upgraded to a newer version of signalr.
Using https://github.com/SignalR/SignalR/wiki/Self-host example i have created a simple example, but i can’t get it to work.
I can get a connection to the hub on the server and call methods on the hub, but i can’t get the hub to call the javascript client.
When looking at it in fiddler I never see a response come back from the hub.
Here is the code
using System;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Hosting;
using Owin;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8080/";
using (WebApplication.Start<Startup>(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
}
using Microsoft.AspNet.SignalR;
using Owin;
namespace ConsoleApplication3
{
class Startup
{
// This method name is important
public void Configuration(IAppBuilder app)
{
var config = new HubConfiguration
{
EnableCrossDomain = true,
EnableJavaScriptProxies = true
};
app.MapHubs(config);
}
}
}
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
namespace ConsoleApplication3.Hubs
{
public class Chat : Hub
{
public override Task OnConnected()
{
Notify(Context.ConnectionId);
return new Task(() => { });
}
public void RunTest()
{
Notify(Context.ConnectionId);
}
public void Notify(string connectionId)
{
dynamic testMessage = new
{
Count = 3,
Message = "Some test message",
Timestamp = DateTime.Now
};
String json = JsonConvert.SerializeObject(testMessage);
var context = GlobalHost.ConnectionManager.GetHubContext<Chat>();
context.Clients.Client(connectionId).sendNotification(json);
}
}
}
And here is the client side
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/json2.js"></script>
<script src="Scripts/jquery-1.9.1.js"></script>
<script src="Scripts/jquery.signalR-1.0.1.js"></script>
<script src="http://localhost:8080/signalr/hubs"></script>
<script>
$(function () {
// Proxy created on the fly
var notification = $.connection.chat;
$.connection.hub.logging = true;
// Declare functions that can be run on the client by the server
notification.client.sendNotification = onAddNotification;
notification.client.disconnected = function (connectionid) {
console.log(connectionid);
};
// Testing code only
$("#testButton").click(function () {
// Run test function on server
notification.server.runTest();
});
jQuery.support.cors = true;
// Map the onConnect and onDisconnect functions
notification.client.connected = function () {
alert("Notification system connected");
};
notification.client.disconnected = function () { };
$.connection.hub.url = "http://localhost:8080/signalr";
//$.connection.hub.start();
$.connection.hub.start(function () {
alert("Notification system connected");
});
});
// Process a newly received notification from the server
function onAddNotification(message) {
// Convert the passed json message back into an object
var obj = JSON.parse(message);
var parsedDate = new Date(parseInt(obj.Timestamp.substr(6)));
// Update the notification list
$('#notifications').prepend('<li>' + obj.Message + ' at ' + parsedDate + '</li>');
};
</script>
</head>
<body>
Send test
<ul class="unstyled" id="notifications">
</ul>
</body>
Any ideas would be appreciated, since i am fairly stuck.
Few things in your code:
Change this:
public override Task OnConnected()
{
Notify(Context.ConnectionId);
return new Task(() => { });
}
To:
public override Task OnConnected()
{
Notify(Context.ConnectionId);
return base.OnConnected();
}
Also in your hub:
This function is trying too hard:
public void Notify(string connectionId)
{
dynamic testMessage = new
{
Count = 3,
Message = "Some test message",
Timestamp = DateTime.Now
};
String json = JsonConvert.SerializeObject(testMessage);
var context = GlobalHost.ConnectionManager.GetHubContext<Chat>();
context.Clients.Client(connectionId).sendNotification(json);
}
I'm not even sure why you're passing the connection id (maybe it was meant to be static?)
public void Notify()
{
dynamic testMessage = new
{
Count = 3,
Message = "Some test message",
Timestamp = DateTime.Now
};
Clients.Client(Context.ConnectionId).sendNotification(testMessage);
}
You don't need to serialize twice, we already do it for you.
Remove:
jQuery.support.cors = true;
Never set that.
Also:
// Map the onConnect and onDisconnect functions
notification.client.connected = function () {
alert("Notification system connected");
};
notification.client.disconnected = function () { };
These aren't mapping anything client side. You can't map connected and disconnected from the server to the client. The client has its own events.
Other things:
This should be inside of the start callback so that you don't hit it before it's ready:
$.connection.hub.start().done(function() {
// Testing code only
$("#testButton").click(function () {
// Run test function on server
notification.server.runTest();
});
});

Resources