SignalR fail method not called when user identity changed - signalr

I'm using SignalR but have run into a problem. When a connection is started in one browser window and then a user logs in in another browser window the User identity is changed (this causes the error 'System.InvalidOperationException: Unrecognized user identity. The user identity cannot change during an active SignalR connection' on the server when a method is called on the hub.
I'm using this code on the client:
proxy.server.analyze(content)
.done(function () {
console.log('Success!');
})
.always(function () {
console.log('This is always called!');
})
.fail(function (error) {
console.log('This is never called!');
});
When I'm seeing errors on the server the fail function is never being called so there appears to be no way on the client to handle this problem and stop and start the connection.
So is there a "best practice" way of handling this case? How can I detect on the client that the user identity has changed in another browser window and stop and re-start the connection?

This is a known issue.
It is fixed in the next release. Here's the issue that ended up also fixing your issue: https://github.com/SignalR/SignalR/issues/2106.
Lastly, in the next release (0.2.0) what will happen is the connection will throw an error and stop itself. Therefore you'll be able to handle your case via either the error handler or you can of course you can tie into the "disconnected" event.
If you're willing to try a pre-releases you can always pull from the offical source or webstack nightly (http://www.myget.org/F/aspnetwebstacknightly/)

Related

SignalR Connections break entire site

I'm using SignalR 2.2.2 to send users messages from my backend. When a user is logged in, and if other conditions are met, their connection is added to a group with the user's userId on my message hub.
It works great, as long as they have ~10 or fewer tabs/windows open. Any beyond that, they're stuck in "Loading..." indefinitely.
It seems to just be getting stuck on $.connection.hub.start();
I don't necessarily need to allow each user an infinite amount of signalr connections, but breaking the entire site for them on 10 open tabs is a problem.
OKAY BUT HERE'S THE THING. When I change my project's server setting from Local IIS to IIS Express, this problem vanishes! BUT! When we build the solution & put it on the test server, it's still broken.
What is going on???
I've tried catching or handling an error, but it still just hangs there.
$(function () {
if (loggedInUser != null)
{
var user = loggedInUser.UserId;
var messaging = $.connection.messageHub;
if (conditions) {
$.connection.hub.start().done(function () {
messaging.server.joinGroup(user);
});
}
}
});
I can get this to work with IIS Express. Now I need it to work like that on my test (and then later production) Server.
What else can I even try?

Get detailed error for exception in SignalR Core Hub method execution

When I call Hub method I get frame response:
{"invocationId":"1","type":3,"error":"An error occurred while updating
the entries. See the inner exception for details."}
How can I get detailed error report (row and file where error occurred) without manually debugging and using step over and check where the code raise exception.
On net I found plenty codes where EnableDetailedErrors is used
services.AddSignalR(options =>
{
options.Hubs.EnableDetailedErrors = true;
});
but options (at least in version 1.0.0-alpha2-final) does not have property Hubs.
This is what you need to do in core (not sure the exact version this was added):
// signalR
services.AddSignalR(options =>
{
if (Environment.IsDevelopment()) {
options.EnableDetailedErrors = true;
}
});
It goes without saying that the reason this is disabled by default in production is for security reasons. So be careful not to expose things you may not wish 'hackers' to see in any of the exceptions you may throw.
Implementing the above setting will reveal a more detailed message in the browser console, whcih you can also see in the websocket debugging tab:
Quick tip:
I've set up SignalR twice now on ASPNetCore and I think I've made the same mistake both times:
// from typescript client arguments are passed like this
this.hubConnection.invoke('SendMessage', 'simon', 'hello');
// not like this
this.hubConnection.invoke('SendMessage', ['simon', 'hello']);
Also invoke will wait for a response, while send does not. So you may not see errors using send.
Currently the option to enable detailed errors is not implemented. There is an issue tracking this. My recommendation would be to turn on logging on the server side - the original exception will be logged there.

Firebase authWithOAuthRedirect() woes

I'm trying to update my angularjs app to support Firebase 1.1 (I was stick with Firebase 1.0.x).
It deprecates firebasesimplelogin, including authentication inside Firebase core.
I have been able to successfully implement authentication using
authWithOAuthPopup("<provider>", function(error, authData) { ... });
It accepts a callback, which is passed authentication data in authData.
On the contrary, I can't undersand how to use
authWithOAuthRedirect("<provider>", function(error) { ... });
Firebase Authentication docs page is very concise... :-(. This is all what is said:
Alternatively [instead of authWithOAuthPopup], you may prompt the user to login with a full browser redirect, and Firebase will automatically restore the session when you return to the originating page
How do I get authData, when Firebase - after redirection - returns to my page?
The authData is available by registering a listener directly on the ref (so before calling authWithOAuthRedirect).
ref.onAuth(function(authData) {
...
}
ref.authWithOAuthRedirect("google", function(error) { ... });
See https://www.firebase.com/docs/web/guide/user-auth.html#section-monitoring-authentication
I think I'm running into the same issue as you. I'm trying to do Facebook authentication.
First, I'd like to clarify the reproduction steps for my issue.
My app is loaded on the client.
User clicks login with Facebook.
ref.authWithOAuthRedirect('facebook', ...) is called.
Client is redirected to Facebook and Facebook redirects client back to Firebase app
Despite successful authentication with Facebook, the callback passed to onAuth() is invoked (only once) with authData === null.
The callback passed to onAuth() is not invoked a second time with correct authData.
However, reloading the app causes the callback passed to onAuth to be invoked with correct authData. The reasons for this are not known to me but I suspect race condition.
Here's my workaround.
Before calling ref.authWithOAuthRedirect('facebook', ...) set yourself a flag in sessionStorage.
sessionStorage.reload = true;
ref.authWithOAuthRedirect('facebook', ...)
When the client is redirected to your app back from Facebook, you should be able to check for this flag and reload the page if necessary.
if (sessionStorage.reload) {
delete sessionStorage.reload;
setTimeout(function() {
location.reload();
}, 1000)
}
setTimeout(function() { ... }, 1000) helps fight the assumed race condition. I found 500 ms is insufficient time for the race condition to be resolved.
And one small gotcha: if you reload the page too soon, then authData remains null no matter how many times you reload the page.

Why is my disconnect() handler not getting fired in SignalR Client Side JS?

I'm seeing some odd/unexpected behaviour using the SignalR 2.0.3 libraries.
I'm trying to hook some call backs in the client and they don't seem to be getting fired.
I'd really like to get the reconnecting, reconnected and disconnected call backs working in JS - client side.
SignalR does connect successfully and I've got communication between the server and client.
Here are a couple of code snippets:
$.connection.reconnecting = function () {
alert("reconnecting");
};
$.connection.reconnected = function () {
alert("We have been reconnected");
};
$.connection.disconnected = function () {
alert("We are disconnected!");
};
I could have sworn that I had these firing when I was using SignalR 1.x.
Currently, we using version 2.0.3.
I'm running a 2 machine setup where my server app (and hub) is on 1 machine.
Here are the steps I'm using to reproduce:
1) Connect from a second machine. I looked at the network traffic in the browser
console and it looks ok.
2) Next I disconnect the client machine from the network. In the console I see SignalR
attempting to reconnect. (This is as expected)
3) Ultimately after N retries, it looks like it disconnects. (I see the final retry is "Canceled"
in the console output.
4) However, my disconnected() handler does not get called.
Any insights or thoughts how to track this down?
Thanks,
JohnB
With SignalR 2.x, you can register your callbacks like this:
$.connection.hub.reconnecting(function() {
alert("reconnecting");
});
$.connection.hub.reconnected(function() {
alert("We have been reconnected");
});
$.connection.hub.disconnected(function() {
alert("We are disconnected!");
});
You can also add callbacks using $.connection.hub.stateChanged(). See documentation.

SignalR not always ready after start().done()?

I have got a small project working with SignalR, however i am getting some very inconsistent behavior.
<script type="text/javascript">
$(function () {
var chat = $.connection.brewBattleHub;
$.connection.hub.start().done(function () {
$("#broadcast").click(function () {
// Call the chat method on the server
chat.server.roll($("#username").val(), $("#drinkname").val());
});
chat.server.sendMessage("SignalR loaded...");
});
});
</script>
When i load the page, sometimes i am seeing the message "SignalR loaded", other times i am not.
There's is some other functionality on the page also, and sometimes this does not work either. If i click buttons and make things happen enough it will eventually all come through in one go... from this point it is all golden and works perfectly.
does start().done()? not ensure it is all ready?
===
addendum, i am not referencing jquery mobile (google mentioned there is a bug when doing so)
I had a similar issue this week except that the code in .done() never ran. I enabled logging and nothing was ever logged. Checking the browser's console there were no errors. Looking in the browser's dev tools I could see that there was no network activity when I called start(). I confirmed that the proxy returned by $.connection.myhubclass had all my methods on it so I knew it could talk to the server and that the server side code was set up right.
After reviewing the code and documentation over and over again I was convinced that I wasn't doing anything wrong. SignalR is so simple it's pretty tough to do it wrong if you follow the examples. I beat my head on the desk for quite a long time trying to figure this out.
Then I noticed that if I ran SignalR's start method from the console it would work. That led me to believe that it was trying to start the connection too early. I solved my problems by changing the initialization code from this:
$.connection.hub.start().done(function () {
//Do interesting stuff
});
To this:
setTimeout(function () {
$.connection.hub.start().done(function () {
//Do interesting stuff
});
}, 5000);
I'm sure I can reduce that delay from 5 seconds to something shorter but the extra time appeared to be what was needed to let the browser get itself ready to create the connection. Once that delay was in there the logging started working, the connection came up, the server side OnConnected() ran and done() was run on the client.
After figuring this out I double checked the order of my javascript loading, thinking maybe I was loading something out of order but the order is right according to the SignalR samples. I load jQuery, SignalR, /signalr/hubs, then my script file that initializes everything.
I am open to suggestions as to why that delay was needed. I don't see it in any of the docs so I know it could be something I did. Fortunately for this page a minor delay before starting up SignalR is not a problem.
Try enabling SignalR logging to help debug your issue. You might also want to add a fail handler in case start isn't succeeding (though this is unlikely). Once you have done this you can look through your browser's F12 tools to look at the JS and network logs.
<script type="text/javascript">
$(function () {
$.connection.hub.logging = true;
var chat = $.connection.brewBattleHub;
$.connection.hub.start().done(function () {
$("#broadcast").click(function () {
// Call the chat method on the server
chat.server.roll($("#username").val(), $("#drinkname").val());
});
chat.server.sendMessage("SignalR loaded...");
}).fail(function (reason) {
console.log("SignalR connection failed: " + reason);
});
});
</script>
I've found a solution (as far by my problem).
I had SignalR loading for some 7-8 seconds on IE11, I've tried to "debug" it in console and I've found the cause of the loading delay:
[13:13:04 GMT+0200 (...)] SignalR: Binding to iframe's load event.
[13:13:09 GMT+0200 (...)] SignalR: foreverFrame timed out when trying to connect.
[13:13:09 GMT+0200 (...)] SignalR: Stopping forever frame.
It took 5 sec. to try to load iframe.
The neat solution is to turn the iframe off, as IE11 can normally use longPolling:
$.connection.hub.start(({ transport: ['webSockets', 'serverSentEvents', 'longPolling'] }))
I had a similar issue that only appeared when trying to reestablish the connection after disconnect. I called start() from the disconnect handler and then tried to send a message from start.done(). Then I got an error message that SignalR was not ready.
I noticed in the log that start.done() resolved immediately so there was in my case a call from disconnect to start and then to send. I added a setTimeout in the disconnect handler so that start and send were decoupled from disconnect. That resolved the issue for me.

Resources