I want to push a notification from my server to client. I've tried the chat tutorial found here but this just sends chat messages from one client to client
What I want is a button whose onClick method is running at server. Once, I click this button, notifications (a string message) must be sent to all clients.
My Hub class is
public class NotificationsHub : Hub
{
public void SendNotification(string author, string message)
{
Clients.All.broadcastNotification(author, message);
}
}
and in the button click, I try this
var context = GlobalHost.ConnectionManager.GetHubContext<NotificationsHub>();
context.Clients.All.SendNotification("Admin", "stop the chat");
But still, I'm not able to notify the clients. Nothing is happening. What am I doing wrong??
My JS at client web page to notify is like this
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var notifications = $.connection.notificationsHub;
// Create a function that the hub can call to broadcast messages.
notifications.client.broadcastNotification = function (name, message) {
alert(name + " says '" + message + "'");
};
You need to call broadcastNotification in your button click function, like below:
var context = GlobalHost.ConnectionManager.GetHubContext<NotificationsHub>();
context.Clients.All.broadcastNotification("Admin", "stop the chat");
Also, you need to start the hub by adding $.connection.hub.start(), your JS file should be like:
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.0.1.js"></script>
<script src="/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
var notifications = $.connection.notificationsHub;
notifications.client.broadcastNotification = function (name, message) {
alert(name + " says '" + message + "'");
$.connection.hub.start();
};
</script>
Related
I am new to signalr,
I have gone through a number of tutorials where I have seen the chat room application where server has been configured on console app and client on javascript, as you open the multiple instances of browsers you can chat between them.
My question is how to chat between server to client rather than between clients.
lets say I build a server on winform. On that winform I have datagridview which shows me the number of clients connected to server and I want to send a message to client #2 , then the client #2 will also reply me which I will show in a textbox on winform.
My Client Code:
<script type="text/javascript">
$(function () {
$.connection.hub.url = "http://localhost:8080/signalr";
var chat = $.connection.myHub;
// Create a function that the hub can call to broadcast messages.
chat.client.addMessage = function (name, message) {
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
$('#displayname').val(prompt('Enter your name:', ''));
$('#message').focus();
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
chat.server.send($('#displayname').val(), $('#message').val());
$('#message').val('').focus();
});
});
});
</script>
Myhub.cs:
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
public void getname(string name)
{
}
public override Task OnConnected()
{
UserHandler.ConnectedIds.Add(Context.ConnectionId);
string RemoteIpAddress = Context.Request.GetRemoteIpAddress();
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
UserHandler.ConnectedIds.Remove(Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
public void acknowledgment(string ack)
{
Clients.Caller.acknowledgment(ack);
}
}
Code seems good. try to add following code in startup.cs
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
Scenario
I'm attempting to use linqpad to self host SignalR.
Script
// I have uploaded to instant share here: http://share.linqpad.net/578ol2.linq
// Import the following nuget packages:
// Microsoft.AspNet.SignalR.SelfHost
// Microsoft.Owin.Cors
#define NONEST
void Main()
{
var baseUrl = #"http://localhost:8080/";
using (WebApp.Start<Startup>(baseUrl))
{
Process.Start(baseUrl + "index.html");
Console.WriteLine("Server running at " + baseUrl);
Console.ReadLine();
}
}
public class Startup
{
public readonly string Html = #"
<!DOCTYPE html>
<html>
<head>
<title>SignalR Simple Chat</title>
</head>
<body>
<div class='container'>
<input type='text' id='message' />
<input type='button' id='sendmessage' value='Send' />
<input type='hidden' id='displayname' />
<ul id='discussion'></ul>
</div>
<script src='https://code.jquery.com/jquery-1.6.4.js'></script>
<script src='http://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.0.js'></script>
<script src='http://localhost:8080/signalr/hubs'></script>
<script type='text/javascript'>
$(function () {
$.connection.hub.url = 'http://localhost:8080/signalr';
$.connection.hub.logging = true;
var chat = $.connection.myHub;
chat.client.addMessage = function (name, message) {
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
$('#discussion').append('<li><strong>' + encodedName + '</strong>: ' + encodedMsg + '</li>');
};
$('#displayname').val(prompt('Enter your name:', ''));
$('#message').focus();
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
chat.server.send($('#displayname').val(), $('#message').val());
$('#message').val('').focus();
});
});
});
</script>
</body>
</html>
".Trim();
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
app.Map("/index.html", config =>
{
config.Run(context =>
{
context.Response.ContentType = "text/html";
return context.Response.WriteAsync(Html);
});
});
}
}
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
Outcome
If you look at the browser console you see that SignalR eventually exhausts all transports, so can't create a connection between the client and the server
SignalR: Client subscribed to hub 'myhub'.
Negotiating with 'http://localhost:8080/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22myhub%22%7D%5D'.
serverSentEvents transport starting.
Attempting to connect to SSE endpoint 'http://localhost:8080/signalr/connect?transport=serverSentEvents&clientProt…joHW8a9m5Q%3D%3D&connectionData=%5B%7B%22name%22%3A%22myhub%22%7D%5D&tid=1'.
EventSource connected.
serverSentEvents transport timed out when trying to connect.
EventSource calling close().
serverSentEvents transport failed to connect. Attempting to fall back.
foreverFrame transport starting.
Forever Frame is not supported by SignalR on browsers with SSE support.
foreverFrame transport failed to connect. Attempting to fall back.
longPolling transport starting.
Opening long polling request to 'http://localhost:8080/signalr/connect?transport=longPolling&clientProtocol=…QeRv75joHW8a9m5Q%3D%3D&connectionData=%5B%7B%22name%22%3A%22myhub%22%7D%5D'.
longPolling transport timed out when trying to connect.
Aborted xhr request.
longPolling transport failed to connect. Attempting to fall back.
Fallback transports exhausted.
Stopping connection.
Fired ajax abort async = true.
However this same exact code works without issue within a Console Application
Question
Does anyone know why this code fails when hosting in linqpad but works when hosting in a console application?
I'm leaning towards some sort of connectivity issue rather than a LinqPad one as I'm able to run your code snipped without an issue. I am also running it under version 5. Do you happen to have a 3r party firewall?
Just to confirm, what's the expected behaviour? When I run it, my browser pops up asking me to enter a name. Then I'm able to send 'messages', which appear on the page below the text box.
I have a simple application, like a chat, integrated with SignalR. I added a new method on my Hub and a new function on client side, like you can see below.
The problem is, my method called SendMessageChat isn't firing, because occurs the following error
TypeError: chat2.server.SendMessageChat is not a function
but the method chat2.server.send works fine, and I don't know why my second method doesn't work. Can someone help me ?
JavaScript
$(function () {
var chat2 = $.connection.redirectTask;
chat2.client.broadcastMessage = function (name, message) {
// Do something here
};
chat2.client.sendMessage = function (name, message) {
// Do something here
};
//$.connection.hub.logging = true;
$.connection.hub.start().done(function () {
/* BUTTON CLICK IN ANOTHER PAGE */
$('#btnFinish').click(function () {
chat2.server.send($.cookie("User"), $("#lista :selected").text());
});
/* CASE HIT ENTER INSIDE THE TEXT FIELD IN CHAT */
$(document).on("keypress", "#txtChat", function (e) {
var code = (e.keyCode ? e.keyCode : e.which);
if (code == 13) {
var message = $(this).val();
$(this).val("");
chat2.server.SendMessageChat($.cookie("User"), message);
}
});
});
});
SERVER SIDE
public class RedirectTask : Hub
{
public void Send(string nome, string message)
{
Clients.All.broadcastMessage(name, message);
}
public void SendMessageChat(string nome, string message)
{
Clients.All.sendMessage(name, message);
}
}
Reference
Need to change to
chat2.server.sendMessageChat($.cookie("User"), message);
Camel-casing of method names in JavaScript clients
By default, JavaScript clients refer to Hub methods by using a camel-cased version of the method name. SignalR automatically makes this change so that JavaScript code can conform to JavaScript conventions.
Server
public void NewContosoChatMessage(string userName, string message)
JavaScript client using generated proxy
contosoChatHubProxy.server.newContosoChatMessage(userName, message);
If you want to specify a different name for clients to use, add the HubMethodName attribute.
Server
[HubMethodName("PascalCaseNewContosoChatMessage")]
public void NewContosoChatMessage(string userName, string message)
JavaScript client using generated proxy
contosoChatHubProxy.server.PascalCaseNewContosoChatMessage(userName, message);
I have created a sample signalR for POC.
I want to call a hub method from Global.asax and pass a string value to client.
My Message hub is :-
[HubName("messageHub")]
public class MessageHub : Hub
{
public static IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessageHub>();
public void Message()
{
/*
* services and updates the messages
* property on the PushMessage hub
*/
//IHubContext context = GlobalHost.ConnectionManager.GetHubContext<SignalR_Error_Logging.Models.ErrorModel>();
List<GenerateError.Repository.ErrorModel> model = ErrorRepository.GetError();
context.Clients.pushMessages(model[0].ErrorMessage);
}
I have defined two of the scripts in layout.cshtml
<script type="text/javascript" src="../../Scripts/jquery-1.6.4.js"></script>
<script type="text/javascript" src="../../Scripts/jquery.signalR-0.5.3.js"></script>
My Index.html is as below:-
#{
ViewBag.Title = "Receive Error message";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script src="/signalr/hubs" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
var myHub = $.connection.messageHub;
myHub.pushMessages = function (value) {
console.log('Server called addMessage(' + value + ')');
$("#messages").append("<li>" + value + "</li>");
};
$("#btnMessage").click(function () {
myHub.message();
});
$.connection.hub.start().done(function () { alert("Now connected!"); }).fail(function () { alert("Could not Connect!"); });
});
</script>
<h2>Receive Error Messages</h2>
<ul id="messages"></ul>
<input type="button" id="btnMessage" value="Get Error" />
In Global.asax
I have written
SignalR_Error_Logging.SignalRHub.MessageHub hub = new SignalRHub.MessageHub();
hub.Message();
In Application_Start();
I am not able to display message in my UI(i.e Index.cshtml).
Things that i have tried:-
Running the application as IIS.
Changing the way of creating HubContext.
IHubContext _context = GlobalHost.ConnectionManager.GetHubContext<MessageHub>();
context.Clients.notify("Hello world");
if (Clients != null)
{
Clients.shootErrorMessage(message);
this.Clients.shootErrorMessage(message);
}
Gone thru links of StackoverflowCalling SignalR hub clients from elsewhere in system
Any advice???
When i call my hub method by creating a button in Index.html it works fine.
Apologies for not framing my question properly!!
I figured out, way of calling the Hub was not correct.
For the time being i have modified my code as in Global.asax :-
private void CallSignalR()
{
var context = SignalR.GlobalHost.ConnectionManager.GetHubContext<SignalR_Error_Logging.SignalRHub.MessageHub>();
List<GenerateError.Repository.ErrorModel> err = GenerateError.Repository.ErrorRepository.GetError();
foreach (var item in err)
{
item.ErrorDescription = item.ErrorDescription + DateTime.Now.ToString();
}
context.Clients.pushMessages(err);
}
Works absolutely fine now :)
Still figuring out better alternatives !!!!
This will never work. Application_Start() in Global.asax is only called once for the lifetime of your AppDomain. It happens when the website starts up and at this point in time, no clients are connected yet (as the website isn't fully initialized) so you can't send messages via SignalR.
I have hub class:
public class ChatHub : Hub
{
// Send message
public void Send(string message)
{
Clients.addMessage(DateTime.Now.ToString("HH:mm:ss") + " " + message);
}
}
And javascript:
// Proxy created on the fly
var chat = $.connection.chatHub;
// Declare a function on the chat hub so the server can invoke it
chat.addMessage = function(message) {
alert("message:" + message);
$('#chat').append('<div>' + message + '</div>');
};
$("#sendButton").click(function () {
// Call the chat method on the server
chat.send($('#message').val())
.done(function () {
console.log('Success!')
})
.fail(function (e) {
console.warn(e);
})
});
// Start the connection
$.connection.hub.start();
All conection are fine:
If I use breakpoint in here Clients.addMessage(DateTime.Now.ToString("HH:mm:ss") + " " + message); everything is fine.
But i don't get callback on javascript function.
alert("message:" + message); never executes
Did you add the client side Signalr hub?
<script src="/signalr/hubs" type="text/javascript"></script>