SignalR Client in PartialView Not Receiving - c#

I'm still getting the basics of SignalR down. I'd like to use it in different parts of my website, so I was thinking I could start the connection in the main layout, and add client methods in sub views.
As per this answer I have :
window.hub = $.connection.hub.start();
in my Layout.cshtml, and
window.hub.done(function () {
$.connection.notificationHub.server.joinScannerGroup(1);
alert("in sub view");
});
in my subview, which works. The hub is connected, and the method JoinScannerGroup() is called. However, if i try to add:
$.connection.notificationHub.client.scanReceived = function (text) {
alert("scan received");
};
anywhere in the javascript for the subview, it never gets called. Maybe I'm undertanding it wrong, but I'd like to connect on the mainpage, and then allow any subpages to receive client calls.
Also, if I move the $.connection.start() into the subview, it does work correctly. Am I understanding it wrong?

You need to either add all client hub methods before you call hub.start(), or you need to add at least one hub method before calling hub.start() (so SignalR will subscribe to the hub) and then add all other hub methods like this:
$.connection.notificationHub.on('scanReceived ', function (text) {
alert("scan received");
});
(also see documentation)

Related

Unity PUN RPC call from another class

Trying to call a RPC from another class. But seems like It doesn't work. How can I fix this?
Using 3 RPC in same function. So I tried to call function without RPC in a RPC function(This RPC in same class so it works flawlessly) but it doesn't work either I suppose.
chambers[i].Bullet.Fire(muzzle);// Without RPC code:
photonView.RPC("chambers["+i+"].Bullet.Fire", RpcTarget.All, new object[] { muzzle });// With RPC
Made a Debug log in Fire function. So when it works I should see it. But when I press the button I get this log(By the way i dont get this in other RPC calls).
Sending RPC "chambers[0].Bullet.Fire" to target: All or player:.
Add photon view to the bullet, and call Fire directly on it.
chambers[i].Bullet.photonView.RPC("Fire", RpcTarget.All, new object[] { muzzle });

ASP.NET Core 2.2 SignalR Buffering Calls Instead of Invoking Asynchronously

I'm writing an ASP.NET Core 2.2 C# web application that uses SignalR to take calls from JavaScript in a web browser. On the server side, I initialize SignalR like this:
public static void ConfigureServices(IServiceCollection services)
{
...
// Use SignalR
services.AddSignalR(o =>
{
o.EnableDetailedErrors = true;
});
}
and
public static void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
// Route to SignalR hubs
app.UseSignalR(routes =>
{
routes.MapHub<ClientProxySignalR>("/clienthub");
});
...
}
My SignalR Hub class has a method like this:
public class ClientProxySignalR : Hub
{
...
public async Task<IEnumerable<TagDescriptor>> GetRealtimeTags(string project)
{
return await _requestRouter.GetRealtimeTags(project).ConfigureAwait(false);
}
...
}
and on the client side:
var connection = new signalR.HubConnectionBuilder()
.withUrl("/clienthub")
.configureLogging(signalR.LogLevel.Information)
.build();
connection.start().then(function () {
...
// Enable buttons & stuff so you can click
...
}
document.getElementById("tagGetter").addEventListener("click", function (event) {
connection.invoke("GetRealtimeTags", "Project1").then(data => {
...
// use data
...
}
}
This all works as far as it goes, and it does work asynchronously. So if I click the "tagGetter" button, it invokes the "GetRealtimeTags" method on my Hub and the "then" portion is invoked when the data comes back. It is also true that if this takes a while to run, and I click the "tagGetter" button again in the meantime, it makes the .invoke("GetRealtimeTags") call again...at least in the JavaScript.
However...this is where the problem occurs. Although the second call is made in the JavaScript, it will not trigger the corresponding method in my SignalR Hub class until the first call finishes. This doesn't match my understanding of what is supposed to happen. I thought that each invocation of a SignalR hub method back to the server would cause the creation of a new instance of the hub class to handle the call. Instead, the first call seems to be blocking the second.
If I create two different connections in my JavaScript code, then I am able to make two simultaneous calls on them without one blocking the other. But I know that isn't the right way to make this work.
So my question is: what am I doing wrong in this case?
This is by design of websockets to ensure messages are delivered in exact order.
You can refer to this for more information: https://hpbn.co/websocket/
Quoted:
The preceding example attempts to send application updates to the
server, but only if the previous messages have been drained from the
client’s buffer. Why bother with such checks? All WebSocket messages
are delivered in the exact order in which they are queued by the
client. As a result, a large backlog of queued messages, or even a
single large message, will delay delivery of messages queued behind
it—head-of-line blocking!
They also suggest a workaround solution:
To work around this problem, the application can split large messages
into smaller chunks, monitor the bufferedAmount value carefully to
avoid head-of-line blocking, and even implement its own priority queue
for pending messages instead of blindly queuing them all on the
socket.
Interesting question.
I think the button should be disabled and show a loading icon on the first time it is clicked. But maybe your UI enables more than one project to be loaded at once. Just thought for a second we might have an X-Y problem.
Anyways, to answer your question:
One way you can easily deal with this is to decouple the process of "requesting" data from the process of "getting and sending" data to the user when it is ready.
Don't await GetRealtimeTags and instead start a background task noting the connection id of the caller
Return nothing from GetRealtimeTags
Once the result is ready in the background task, call a new RealtimeTagsReady method that will call the JavaScript client with the results using the connection id kept earlier
Let me know if this helps.

How to debug SignalR server event that fails to fire from client?

When I copy the code from this tutorial into my current project, I have no problems using their Send method.
However, in my own code, my server Send method never fires.
Server code:
public class ModelingHub : Hub
{
public void Send(string message) // my breakpoint is never hit here
{
Clients.All.broadcastMessage(message);
}
}
Client Code
$(function () {
var modelHub = $.connection.modelingHub;
modelHub.client.broadcastMessage = function(response) {
alert(response);
};
$.connection.hub.start().done(function () {
alert(1); // this fires
$("body").on("click", function () {
alert(2); // this fires too
modelHub.server.send("test"); // never fires
});
});
});
I don't want to go messing with the library code from SignalR, but I'm not sure how to debug this any further.
I can't call the method from the console either:
>$.connection.modelingHub.server.send("test")
Note that when I implement OnConnected and OnDisconnected events in my ModelingHub subclass, they work fine. I've taken them out to debug the Send failure.
Your issue stems from your class, you do the following:
public class ModelingHub : Hub
{
public void Send(string message)
{
var call = message;
}
}
But you aren't actually doing anything with your message, you need your hub to actually broadcast the data. You would need to add code similar or this below your variable call.
Clients.All.broadcastMessage(call);
If you don't sanitize your data, the method body could be:
public void Send(string message) => Clients.All.broadcastMessage(message);
Also, if I recall that tutorial has an interface called Send which expects two parameters, you may want to also check there to ensure you modified to accept your single parameter.
Make sure that you reference the correct version of SignalR. The tutorial references version 2.2.1 but the current version is 2.2.2 so that is a potential issue.
Check the browser console to see if you have any errors and make sure the version numbers of the references match up with what you have in your project.

How Can I Manually Add Connections to Groups with Multiple Hubs in SignalR

I have two hubs, call them NotificationHub and ReminderHub. Think of NotificationHub as the main hub, and ReminderHub as an optional hub that I wish to separate from NotificationHub. Clients will connect to NotificationHub with the following typical server hub method.
public override Task OnConnected()
{
return base.OnConnected()
}
with corresponding client connection
$.connection.hub.start().done(function() {
subscribeToReminderHub();
});
subscribeToReminderHub(); contains the following
subscribeToReminderHub = function() {
reminderProxy = $.connection.reminderHub;
reminderProxy.server.subscribe().done(function() {
console.log('subscribed to reminder hub...');
});
}
reminderProxy.server.subscribe() refers to the following server method on ReminderHub
public async Task Subscribe()
{
var currentUser = Context.User.Identity.Name.ToUpperInvariant();
await Groups.Add(Context.ConnectionId, currentUser);
}
This all works as I would tyically expect. I can hit a break point on the server Subscribe() method, as well as log out
subscribed to reminder hub...
However, if I try to then invoke methods on users in the groupings I am trying to establish in ReminderHub, nothing will occur. I have defined two client functions inside my initial connection .done() callback. Consider the following example
public void Notify() // ... ReminderHub
{
// ***** notification chain - step 2
// ***** this never gets called
var userId = Context.User.Identity.Name.ToUpperInvariant();
Clients.Caller.notify();
}
// **** $.connection.hub.start().done(function() { **** callback
subscribeToReminderHub = function() {
reminderProxy = $.connection.reminderHub;
reminderProxy.server.subscribe().done(function() {
console.log('subscribed to reminder hub...');
});
reminderProxy.client.queryNotifications = function () {
// ***** notification chain - step 1
// ***** this never gets called
reminderProxy.server.notify();
}
reminderProxy.client.notify = function () {
// ***** notification chain - step 3
// ***** this never gets called
}
}
Starting this notification chain, I am invoking Notify() external from the hub like... note: I am passing userId which would relate back to the grouping
GlobalHost.ConnectionManager.GetHubContext<ReminderHub>().Clients.Group(userId).queryNotifications();
The most interesting part of this whole issue
is that if I don't introduce a second hub, and establish the group on NotificationHub's OnConnected and re-factor all logic back to the sole hub, this entire process works as expected. Somehow introducing a second hub and trying to establish a group outside of OnConnected is not working. Has anyone experienced this? Thoughts?
Even more interesting! (and awful!)
if I open up my browser dev tools and explicitly paste the following into my console
reminderProxy.server.notify()
I hit the breakpoint on ReminderHub's Notify()!
I continue through Clients.Caller.notify(); and the client function .notify() does not even get called in my client JS. I can't understand that at all. Bypassing all groping concerns, I can't even hit a client function now that I've introduced ReminderHub
You should make sure you prepare all of your client-side event handlers before starting the connection, otherwise SignalR will not fulfill them (at least in its current version).

Does my SignalR Hub class need any methods?

According to the documentation I have read, in order to send a message to a client, I just need to call:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.All.foo(msg);
So... does the Hub class need any methods? If not, then all I have is an empty class:
public class MyHub : Hub
{
}
which just seems like a pointless setup. Am I implementing this incorrectly? because it makes more sense to have methods in a hub class, and then call those methods to send a message to the client.
Also, in the hub itself, I can access Context.connectionId, so that I can get the requestor's connection Id and then stop the message from being fired to that client.... If a Hub shouldn't have methods, then is there a way to access the requestor's connection id?
Yes, you need an empty HUB class declaration, because - It is actually just a proxy between the JS client and the controller so it could be empty since all methods are called via the Clients dynamic variable.
I mean without this , you can work, but you have to write JS for that. This is explained briefly in following link.
For more info refer this link - http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-javascript-client#genproxy

Categories