How to call from server to client with SignalR? - signalr

I'm following "Broadcasting over a Hub from outside of a Hub", but my client browser isn't getting any messages. No errors either. It's like signalR doesn't know about my browser when it comes time to pull the hubContext and send messages.
However, my hub DOES act as expected when calling from client to hub.
My hub:
[HubName("myHub")]
public class MyHub : Hub
{
public void SaySomething(string message)
{
Clients.say(message);
}
public void SayHelloWorld()
{
Clients.say("hello world");
}
}
Code from other place and time in server:
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.say(message);
And my client script:
<script src="Scripts/jquery.signalR-0.5.3.js" type="text/javascript" > </script>
<script src="signalr/hubs"> </script>
<script type="text/javascript">
var hub = $.connection.myHub;
$.extend(hub, {
Say: function(message) {
alert(message); //this only works when the sayHelloWorld() method is executed
}
});
$.connection.hub.start()
.done(function(){
hub.sayHelloWorld(); //this works
});
</script>

If you are using the latest nuget package (v 1.0.1) try:
$.extend(hub.client, {
say: function(message) {
alert(message); //this only works when the sayHelloWorld() method is executed
}
And:
$.connection.hub.start()
.done(function(){
hub.server.sayHelloWorld(); //this works
});
SignalR defined client and server properties for the hub, I was trying the MoveShape sample from a video and faced the same issue.
Hope it helps,

Related

Sending Signalr message from hub to signal has no effect

I have a asp.net net core application, where I want to send a message from the hub to the client (the converse is already working for me).
So I have this controller action, where I am injecting my Hub into:
public IActionResult to()
{
_hub.Clients.All.SendAsync("ReceiveMessage", "user", "message");
return View("~/Views/msg/ClientReceiver.cshtml");
}
So, it's basically just sending a message, and returning a view.
here's the view:
<!DOCTYPE html>
<html>
<body>
<button onclick="receive()">Receive msg from server</button>
<script src="~/lib/signalr/signalr.js"></script>
<script src="~/js/ClientReceiver.js"></script>
</body>
</html>
and the ``ClientReceiver.js` file that is being referenced looks like so:
function receive() {
const connection = new signalR.HubConnectionBuilder()
.withUrl("/NotificationHub")
.configureLogging(signalR.LogLevel.Information)
.build();
connection.on("ReceiveMessage", (user, message) => {
alert(message);
});
}
When looking at the documentation (going to the heading "Call client methods from the hub"), then it seems like this should work.
This does'nt work though, no Alert message appears when it should.
The console in my browser indicates that the correct connection has been established though:
[2021-06-24T23:11:48.359Z] Information: Normalizing '/NotificationHub' to 'https://localhost:44385/NotificationHub'.
When you enter the to method to return to your ClientReceiver.cshtml page, your ClientReceiver is not connected yet, so the page cannot receive your message, you should rewrite a method, and visit the method every time you click the button and send message.
You can try to change your ClientReceiver.js like below:
function receive() {
$.ajax({
url: '/home/send',
type: 'get',
});
}
var connection = new signalR.HubConnectionBuilder()
.withUrl("/NotificationHub")
.build();
connection.on("ReceiveMessage", function (user,message) {
alert(message);
});
connection.start();
Controller:
private readonly IHubContext<NotificationHub> _hub;
public HomeController( IHubContext<NotificationHub> hub)
{
_hub = hub;
}
public IActionResult To()
{
return View("~/Views/msg/ClientReceiver.cshtml");
}
public async Task SendAsync()
{
await _hub.Clients.All.SendAsync("ReceiveMessage", "user", "message");
}
Test result:

Call SignalR Client Method on Startup

I want to call a client side method from my SignalR hub class only once, when the client first loads up the webpage. How would I go about doing this?
In your BlahBlahHub class, you have access to all of the connection methods that you do on the Client. Hint: Look at the base Hub class.
With that being said, here's what the code would look like:
Hub
[HubName("messageHub")]
public class MessageHub : Hub
{
public override Task OnConnected()
{
Clients.Caller.alertUser(88);
return base.OnConnected();
}
}
Client
var sender = $.connection.messageHub;
$.connection.hub.start().done(function () {
}).fail(function (reason) {
console.log("SignalR connection failed: " + reason);
});
sender.client.alertUser = function (test) {
alert(test);
};

SignalR - unable to call server method from external JavaScript client

I am learning SignalR. Using a tutorial I managed to create a very simple ASP.NET MVC based SignalR Server. This is the code of the hub:
[HubName("echo")]
public class EchoHub : Hub
{
public void Say(string message)
{
Trace.WriteLine(message);
}
}
This is my Startup file:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
}
Next I created a HTML/JavaScript based client, that was in the same project as the server code. This client works correctly, when I debug the application, the Output window displays my message. This the code of the first client:
<script src="../Scripts/jquery-1.10.2.min.js"></script>
<script src="../Scripts/jquery.signalR-2.1.2.min.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function() {
var hubProxy = $.connection.echo;
$.connection.hub.logging = true;
$.connection.hub
.start()
.done(function () {
hubProxy.server.say('Hello SignalR');
});
})
</script>
The last thing I wanted to do is to create an client in separate project. I changed a little bit the code, mostly by adding the url's of the server. But this client don't work properly. This is the code of the client:
<script src="Scripts/jquery-1.6.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.0.min.js"></script>
<script src="http://localhost:51644/signalr/hubs"></script>
<script>
$(function() {
$.connection.hub.url = 'http://localhost:51644/signalr';
var hubProxy = $.connection.echo;
$.connection.hub.logging = true;
$.connection.hub
.start()
.done(function () {
hubProxy.server.say('Hello SignalR');
});
})
</script>
The JavaScript don't even enters the function in the done method after starting the connection. But in console on Chrome there are no errors or exceptions being thrown.
So the question is what am I doing wrong in the second client?
EDIT: I enabled and checked the SignalR client logs in Chrome console. The second client is stoping by step "SignalR: Negotiating with '/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%5D'." No errors are returned, everything seems alright, but the client cannot go past this step.
EDIT2: According to the comment from JF Beaulieu the negotiate return 200 status code, but nothing else. After the negotiate there should be next steps, like invoking Say, but in the external client hangs on the negotiate. I paste here console outputs from the build in and external JavaScript client.
Build in client output:
External client output:
The second screenshot shows, that the client stops executing on the negotiate step.
I've also tried the solution of Mareq, but adding the jsonp attribute didn't help.
EDIT3: I add here a link to my Github repo with this project, the server is in the AspNetServer project and client in JavaScriptClient project, hope that helps:
https://github.com/RomanSuska/SignalRSandbox
I finally found the solution of my problem and it's stupid simple. The problem was with the SignalR JavaScript file version, on the server I used version 2.1.2 of SignalR and on the client I used 2.2.0. When I switched the version of the client to 2.1.2 everything started to work.
My case was due to my Hub having a constructor because I was trying to do Dependency Injection with Unity. After I removed the constructor, everything worked.
Add this argument to start:
$.connection.hub.start({ jsonp: true });
EDIT I hosted SignalR in console app and I used simple set configuration:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR(new HubConfiguration { EnableJSONP = true });
}
}
and client code I used like this:
$(function () {
var hub = $.connection.serviceHub;
$.connection.hub.url = 'http://mareq.ddns.net:8087/signalr';
$.connection.hub.start({ jsonp: true });
...
});

The On event on the SignalR Client Hub does not get called

I seem to have an issue with SignalR's JS Client Hub.
The problem is that the 'on' handler does not seem to work - it generates no error but doesn't receive any signals sent by the server.
The code below shows an extract where I call the server (using the invoke) which works fine - then on the server I call back to acceptHubData which should be picked up on the client but isn't.
My objective is when navigating to pages that each page will open a connection to a specific hub and releases this connection when the user moves to another page!!
EDIT: using the following code snippet works but I wonder why the code further below using the 'on' event doesn't work!
var superHub = $.connection.mySuperHub;
superHub.client.acceptHubData = function (data) {
$('<li>hello there' + data + '</li>').prependTo($('#ul1'))
}
$.connection.hub.start().done(function () {
$('<li>done phase 1</li>').prependTo($('#ul1'))
});
Any help would be much appreciated!
This is the client code (in js)
$(document).ready(function () {
var myHub;
try {
var connection = $.hubConnection();
connection.start().done(function () {
myHub = connection.createHubProxy("mySuperHub");
myHub.on('acceptHubData', function (data) {
alert(data); // THIS IS NOT CALLED!
});
myHub.invoke('AcceptSignal', "hello from the client2");
});
}
catch (e) {
alert(e.message);
}
});
This is the Server code:
[HubName("mySuperHub")]
public class MyHub : Hub
{
private readonly HubEngine _hubEngine;
public MyHub() : this(HubEngine.Instance) { }
public MyHub(HubEngine hubEngine)
{
_hubEngine = hubEngine;
}
public void AcceptSignal(string msg)
{
Clients.Caller.acceptHubData("hi");
Clients.All.acceptHubData("hi");
}
}
You can still use the on method to add events for JS client hub method calls in the latest version of SignalR, but if you do not add any event listeners to a hubProxy before calling hubConnection.start(), you will not be subscribed to the hub. SignalR subscribes to the hubs you have event handlers for when the hubConnection starts. If you are not subscribed to your hub, adding any events to that hub after start() won't work.
If you add at least one event listener to the hub before start(), even if it doesn't do anything, you can then add any additional event handlers you want to the hub using on after start() and your handlers will be called.
It doesn't matter if you add an event using hubProxy.on('eventName', function (... or autogeneratedHubProxy.client.eventName = function (... before you call start(), but only on will successfully add event listeners after start() is called.
Not sure which version of SignalR you are using, but I have had more success using the following syntax on my server:
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.All.acceptHubData("hello");
and on my clients:
myHub.client.acceptHubData = function (data) {
console.log(data);
}

Calling method of SignalR from Global.asax (MVC 3)

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.

Resources