Signalr Owin simple example javascript client not being called - signalr

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();
});
});

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

SignalR : How can I broadcast message to Other page of the application

I am creating a test app, where one can download some files and on download success notification will be propagated to admin ,something like notification in
www.ge.tt,or panel notification in Facebook.
I have two pages
a)Download.aspx
b)LandingPage.aspx
In Download.aspx
function PushNotification() {
alert("I ran Upto Here");
//Declare a proxy to Reference a Hub
var notification = $.connection.notificationHub;
//Start a Connection
$.connection.hub.start().done(function () {
notification.server.send(21);
//$("#hdnFileId").val()
alert("I ran Upto Here 2 ");
});
notification.client.broadcastMessage = function (FileID) {
alert("file was Downloaded" + FileID);
};
}
Here two different tabs/browser are working Fine showing alert message if page Loads.
but i want to use the brodcast message in my LandingPage.aspx
here is the Js
$(function () {
var notification = $.connection.notificationHub;
notification.client.broadcastMessage = function (FileID) {
alert("file was Downloaded" + FileID);
};
});
And my hubclass ..
namespace TestApplication.Entities
{
public class NotificationHub : Hub
{
//public void Hello()
//{
// Clients.All.hello();
//}
public void Send(int FileID)
{
Clients.All.broadcastMessage(FileID);
}
}
}
but the notification is not coming here, whats wrong Here?
You didn't start connection in LandingPage.aspx
Try like this in LandingPage.aspx
var notification = $.connection.notificationHub;
$.connection.hub.start();
notification.client.broadcastMessage = function (FileID) {
alert("file was Downloaded" + FileID);
};

How to send a STOMP message with Spring4 when controller is mapped

I have the following code...
#Controller
#RequestMapping("/stomp/**")
public class StompController {
#MessageMapping("/hello")
#SendTo("/topic/greet")
public Greeting greet(HelloMessage message) throws Exception{
System.out.println("Inside the method "+message.getName());
Thread.sleep(3000);
return new Greeting("Hello, "+message.getName()+"!");
}
}
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/stomp/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp/hello").withSockJS();
}
}
<script type="text/javascript">
var stompClient = null;
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
document.getElementById('response').innerHTML = '';
}
function connect() {
var socket = new SockJS('/stomp/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/stomp/topic/greet', function(greeting){
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
stompClient.disconnect();
setConnected(false);
console.log("Disconnected");
}
function sendName() {
var name = document.getElementById('name').value;
stompClient.send("/stomp/app/hello", {}, JSON.stringify({ 'name': name }));
}
function showGreeting(message) {
var response = document.getElementById('response');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(message));
response.appendChild(p);
}
</script>
The Client side code seems to connect fine but I don't see the console message meaning to me "/stomp/app/hello" is the wrong path. What should the proper path be?
I also tried /app/stomp/hello no dice...
Update
I can remove the #RequestMapping("/stomp/**") and remove the stomp related stuff and it works fine for my simple test, however, I need it to work for a more complex application that will not allow this.
#RequestMapping and #MessageMapping annotations can be used in similar ways, but are totally different.
#MessageMapping can also be used at the type level (see reference documentation), so you could annotate your controller with #MessageMapping("/stomp/**").
Nothing prevents you from annotating a Controller with both #MessageMapping and #RequestMapping - similar programming model, different purposes.

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();
},

Resources