Signalr Exception in Browser - asp.net

I am trying to create a chat application but after successful build of the web app its catching an exception when i am passing the paramaters for chat.The exception is
0x800a139e - JavaScript runtime error: SignalR: Connection must be
started before data can be sent. Call .start() before .send()
The screen shots are attached here

You need to make sure you don't try invoking server-side hub methods until start is done. Ex:
$.connection.hub.start().done(function(){
$('#submit').click(function () {
$.connection.chat.server.addMessage($('#msg').val());
})
});
Notice that the event handler isn't wired up until the connection is established.

Related

Why is this SignalR messages being received multiple times?

I am using SignalR in a Blazor server-side app. I added the Microsoft.AspNetCore.SignalR.Client Nuget package (v5.0.11) to the project, and used the following code to create the hub connection...
HubConnection hubConnection = new HubConnectionBuilder()
.WithUrl("url")
.Build();
await hubConnection.StartAsync();
I then send out a message with the following code (Debug.WriteLine added to confirm what's going on)...
Debug.WriteLine($"{DateTime.Now.ToLongTimeString()} SignalR msg sent");
await hubConnection.SendAsync("Send", "Hello");
The component that is to handle such messages creates the hub connection and hooks up to the On handler as follows...
HubConnection hubConnection = new HubConnectionBuilder()
.WithUrl("url")
.Build();
hubConnection.On<string>("Receive", msg =>
Debug.WriteLine($"{DateTime.Now.ToLongTimeString()} SignalR msg received - {msg}"));
await hubConnection.StartAsync();
When the message is sent out, it is definitely only being sent once (which I can confirm from the output panel, where I only see the "sent" output once), but it is received twice.
Searching around, it seems that a common reason for this is if jQuery was loaded twice. However, I have checked this, and it's not the case. It's only being loaded the once. Furthermore, one of the other developers on the team tried it, and he got the message received 15 times! Even if we had accidentally included jQuery twice, we certainly didn't include it 15 times. Also, he's using exactly the same code as me (checked out from source control), so we should get the same results if this were the issue.
Anyone any idea why this could be happening? Thanks
This can occur when you initialise a HubConnection within a component and don’t configure IDispose or IAsyncDispose on your component to dispose the HubConnection.
In a Blazor Server-Side application there is already a SignalR host pushing updates to the client.
If you want to push updates from a page you can use a Singleton Service to handle the communication.
If you set up your own SignalR hub and use the SignalR client in your components, your application is something like the diagram below:
As you can see, the client is actually running on the server. The SignalR hub you've added adds processing and memory overhead and does not add any value.
I created a simple sample app that uses a service that clients listen to for updates:
https://github.com/conficient/BlazorServerWithSignalR

SignalR client disconnected on Azure slots swap

I have web app on Azure with 2 slots.
Whenever the slot swap happens, all SignalR clients are disconnected and not even notified about the connection loss.
SignalR events such a Close, Error, Reconnected are never fired on the client.
How to prevent this or at least know when disconnect happens? (of course I need to avoid polling)
How to prevent this or at least know when disconnect happens?
We could enable SignalR tracing to view diagnositc infomration about events in your SignalR application. How to enable and configure tracing for SignalR servers and clients, we could refer to this document.
Detecting the reason for a disconnection
SignalR 2.1 adds an overload to the server OnDisconnect event that indicates if the client deliberately disconnected rather than timing out. The StopCalled parameter is true if the client explicitly closed the connection. In JavaScript, if a server error led the client to disconnect, the error information will be passed to the client as $.connection.hub.lastError.
C# server code: stopCalled parameter
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
if (stopCalled)
{
Console.WriteLine(String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId));
}
else
{
Console.WriteLine(String.Format("Client {0} timed out .", Context.ConnectionId));
}
return base.OnDisconnected(stopCalled);
}
JavaScript client code: accessing lastError in the disconnect event.
$.connection.hub.disconnected(function () {
if ($.connection.hub.lastError)
{ alert("Disconnected. Reason: " + $.connection.hub.lastError.message); }
});
More details we could refer to Detecting the reason for a disconnection.
How to prevent this?
We could continuously reconnect it.
In some applications you might want to automatically re-establish a connection after it has been lost and the attempt to reconnect has timed out. To do that, you can call the Start method from your Closed event handler (disconnected event handler on JavaScript clients). You might want to wait a period of time before calling Start in order to avoid doing this too frequently when the server or the physical connection are unavailable. The following code sample is for a JavaScript client using the generated proxy.
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
More details we could refer to How to continuously reconnect

Spring WebFlux Broken Stream Error Handling

I'm struggling to find any good examples on how to implement error handling with Spring WebFlux.
The use case I want to handle is notifying HTTP clients that a stream has terminated unexpectedly. What I have found it that with the out of the box behaviour, when a stream is terminated, for example by raising a RuntimeException after x items have been processed, is handled too gracefully! The client is flushed all items up until the exception is raised, and then the connection is closed. As far as the client is concerned the request was successful. The following code shows how this has been setup:
public Mono<ServerResponse> getItems(ServerRequest request) {
Counter counter = new Counter(0);
return ServerResponse
.ok()
.contentType(MediaType.APPLICATION_STREAM_JSON)
.body(operations.find(query, Document.class, "myCollection")
.map(it -> {
counter.increment();
if(counter.getCount() > 500) {
throw new RuntimeException("an error has occurred");
}
return it;
}), Document.class);
}
What is the recommended way to handle the error and notify the HTTP client that the stream terminated unexpectedly?
It really depends on how you'd like to communicate that failure to the client. Should the client display some specific error message? Should the client reconnect automatically?
If this is a "business error" that doesn't prevent you from writing to the stream, you could communicate that failure using a specific event type (look at the Server Sent Events spec).
Spring WebFlux supports ServerSentEvent<T>, which allows you to control various fields such as event, id, comment and data (the actual data). Using an Flux::onErrorMap operator, you could write a specific ServerSentEvent that has an "error" event type (look at the ServerSentEvent.builder() for more).
But this is not transparent to the client, as you'd have to subscribe to specific events and change your JavaScript code otherwise you may display error messages as regular messages.

SignalR doesn't use 'on' subscription after connection to server is started

I have SignalR working with an Angular client, but I can't get proxy.on() to work if the connection is established before I subscribe to events.
My server method invokes the client method pushToClient on both hubs.
var connection1 = $.hubConnection(); //Works fine since I started connection AFTER subscribing
var proxy1 = connection1.createHubProxy('clientPushHub');
proxy1.on('sendToClient', function (message) {
console.log('This will work: ' + message);
});
connection.start();
var connection2 = $.hubConnection(); // Doesn't work when I start the connection BEFORE subscribing
var proxy2 = connection2.createHubProxy('clientPushHub');
connection2.start();
proxy2.on('sendToClient', function (message) {
console.log('This will not work: ' + message);
});
If I change things so that proxy2 subscribes to pushToClient before starting connection2, it works fine. Also tried doing the 'on' subscription in the start().done() callback but that did not work.
I've downloaded and verified this example works as I expected when subscribing after connecting, and this ASP.NET article/section specifically mentions you can do things in this order if you don't use a generated proxy, which I haven't.
What worked for the asker in this SO question does not work for me.
Any ideas where I might have gone wrong?
Based on this post, it sounds like you have to have at least one event listener prior to calling start. From there you can add more event handlers using the 'on' functionality.
EDIT:
Try this.
proxy2.on('foo',function(){});
connection2.start();
proxy2.on('sendToClient', function (message) {
console.log('This will not work: ' + message);
});
Also this is from the article you linked you for post:
Note: Normally you register event handlers before calling the start method to establish the connection. If you want to register some event handlers after establishing the connection, you can do that, but you must register at least one of your event handler(s) before calling the startmethod. One reason for this is that there can be many Hubs in an application, but you wouldn't want to trigger the OnConnected event on every Hub if you are only going to use to one of them. When the connection is established, the presence of a client method on a Hub's proxy is what tells SignalR to trigger the OnConnected event. If you don't register any event handlers before calling the start method, you will be able to invoke methods on the Hub, but the Hub'sOnConnected method won't be called and no client methods will be invoked from the server.

Unexpected Signalr connection abort in Firefox

I am using SignalR (with cross-domain request), version 2.3.0 for webchat integrated to ASP.NET site. Everything is working fine. But I found strange behaviour of SignalR connection. When I clicked to the reference from tab of the chat for file downloading SignalR connection was aborted and onDisconnected method was triggered in my Hub class. FireBug show me next POST-request:
http://*:81/signalr/abort?transport=longPolling&clientProtocol=1.4&token=eUpLNitKcmR1d2JhTTRvcHNVZmEwcG1EKzYvMElZbmg4aE5yam9xM3k0dz0_IjAsNGJmOWNhODUtNDU2NS00NWExLWFjMTgtNzgyN2FhZDA2Njg1LGxvY2FsaG9zdCI1&State=1&connectionToken=hDXe9xIZtmrapjl1LRwtK9B%2BfYMoeuHka8ctBLaPa0YnjiN9iiFa%2BvFMBHIGpGH0h8qPEDgGZSRGwjMw3Wm1DJi6cUPtZjLca6%2FR2576SGksLAj3lnPN1JWIlxMsn8%2Bf&connectionData=%5B%7B%22name%22%3A%22c%22%7D%2C%7B%22name%22%3A%22voip%22%7D%5D, where * is my domain.
It is reproduced in Mozilla Firefox (version 30.0) for LongPolling or Websocket transports. How I can fix this problem? Or is it bug of SignalR or Firefox?
This bug has been recently filed against SignalR on GitHub. The basic idea is that downloading a file causes Firefox to trigger the window.onbeforeunload event which in turn causes SignalR to close any ongoing connections.
For now, the workaround is to attach a handler to the client's disconnected event that will call $.connection.start again after a short window.setTimeout.
You could also unbind SignalR's onbeforeunload handler: $(window).unbind("beforeunload"). The downside of doing this is that Firefox might not gracefully disconnect when the user leaves the page running SignalR. Without a graceful disconnect, SignalR will wait over 30 seconds before it times out the client and calls the OnDisconnected handler on the Hub or PersistentConnection.
I have managed to use the workaraound explained by halter73 and I have solved the issue described by dudeNumber4 resetting the connectionid inside the disconnect event so that the server kept calling back the right users based on their connectionid without the need to address them by their user or group names.
$.connection.hub.disconnected(function () {
setTimeout(function () {
$.connection.hub.start().done(function () {
$("#mySignalRConnectionIdHidden").val($.connection.hub.id);
});
}, 3000);
});

Resources