SignalR message lost when client is navigating - signalr

I have implemented SignalR successfully.
I am using it to show init conversations between users on the site, so when one wants to chat with someone else, a simple message is sent using SignalR.
This works well, except one situation. If the request is sent the same time as the one supposed to receive it is doing a new page request, like navigating the site, the message is lost.
I can see that the messages expire after 30 seconds in the InProcMessageBus, but I do not think that is the problem, since I am testing on my machine and the page load takes max 1-2 seconds.
So, is this actually by design? Or am I doing it wrong?
Thanks.

This is sort of by design. When a user creates a new connection they get a new clientid by default. This is likely the cause of the issue unless you have defined your own IConnectionIdFactory. If you want to make sure a client always gets the same id you would create your own implementation of this and set it like this:
DependencyResolver.Register(typeof(IConnectionIdFactory), () => new CustomIdFactory());
Extensibility in SignalR - https://github.com/SignalR/SignalR/wiki/Extensibility
Example factory replacement for clientID: http://www.kevgriffin.com/maintaining-signalr-connectionids-across-page-instances/

Related

SignalR - storing client information

I've started experimenting with SignalR. I've been trying to come up with a flexible way of storing information about each connected client. For example, storing the name in a chat app rather than passing it with each message.
At the moment, I have a static dictionary which matches the connectionId to an object which contains these properties. I add to this dictionary on connection, and remove on disconnection.
The issue I'm having is that I don't seem to get all disconnect events. If I close a tab in Chrome, the disconnect seems to go through. However, if I rapidly reload a tab, the disconnect doesn't seem to occur (at least not 'cleanly'). For example, if I reload the same tab over and over, it'll tell me my dictionary has multiple items when it should - in theory still be one.
Is there a standard way of storing this kind of per-connection information? Otherwise, what might be causing the issue I'm having?
You are actually handling connection id data correctly. Ensure that you are only instantiating your user data in OnConnected and uninstantiating it in OnDisconnected.
When spamming refresh on your page there are situations which result in the OnDisconnected event not being triggered immediately. However you should not worry about this because SignalR will actually time-out the connection and trigger the OnDisconnected event after a designated timeout (DisconnectTimeout).
If you do come across scenarios where there is not a 1-to-1 correlation for OnConnected and OnDisconnected events (after a significant amount of time) make sure to file a bug at https://github.com/SignalR/SignalR/issues.
Lastly if you're looking at doing some advanced chat mechanics and looking for some inspiration check out JabbR, it's open source!
https://github.com/davidfowl/JabbR
Hope this helps!

LCDS & Flex - Preventing DuplicateHTTPSession errors after logout

I have a flex/LCDS stack, where I'm finding that after logout, I often (but not always) start receiving Duplicate HTTP Session errors on the client.
Here's the important facts of the stack:
The flex client has a login/logout functionality within the app. The page does not refresh after the logout. (Therefore, the Flex app, and the underlying mx.messaging.FlexClient remains initialised)
A user may have multiple tabs open.
per-client-authentication is set to false - we're trying to achieve SSO (integrating with CAS) so the user principle is bound to the JSession.
The problem is most evident when using long-polling for messaging, and when there are two (or more) tabs open.
The problem is very difficult to reproduce when using RTMP or Streaming channels.
A user is bound to a JSession - ie., if they log in on Tab1, they become logged in on Tab2.
When a user logs out from either tab, the Jsession is invalidated.
Here's my current theory as to what's causing the issue:
Tab1 (T1) Starts client -> Issued ClientId1 (C1) -> JSession1 (J1) created
Tab2 (T2) Starts Client -> Issued ClientId2 (C2) -> Joins J1
T1 logs in -> J1 Unaffected
T2 logs in -> J1 Unaffected
T1 & T2 Both subscribe, start polling over amflongpolling
T1 sends logout -> J1 Invalidated -> J2 created
T2 sends poll (against J1)
T1 logout completes, returns with J2, updates cookie
The last two calls create a conflict, where the LCDS sees the FlexClient appears to be related to 2 JSessions.
As a result, an error along the lines of the following is recieved:
Server.Processing.DuplicateSessionDetected Detected duplicate
HTTP-based FlexSessions, generally due to the remote host disabling
session cookies. Session cookies must be enabled to manage the client
connection correctly.
Note: I've been able to recreate the problem in a stand-alone project. I believe it's not an issue with our application specific code, instead caused by the Stateful / session nature and conflicts between multiple tabs sharing the same session.
In summary, I believe the issue is caused where the session is invalidated on the server as a result of calls from one tab, but before the response is sent to the browser to inform it of the new JSession, calls are issued under the old Jsession.
What are some appropriate strategies to defend against this duplicate session issue?
Update
To clarify, while the scenario is similar to those discussed here, there are subtle differences which make the solutions in that article inappropriate.
Specifically, the article discusses preventing duplicate sessions by controlling the initial creation of JSessions across both browsers, using a JSP, or an orchestrated RemoteObject call.
Flex actually assists in this process by preventing outbound RemoteObject calls until the local FlexClient DSid variable is defined, showing that the initial session has been established.
My scenario differs, because the JSession (& associated LCDS FlexSession / Client-Side FlexClient objects) have already been established once, (using the techniques discussed in that article) and subsequently invalidated via logout - which calls session.invalidate() - destroying the JSession.
The issue arises when Tab2 sends a call with a stale JSession, a duplicate HTTP Session error. The situation then gets compounded, as when LCDS throw the DuplicateHTTPSession error, it also invalidates all known Jsessions attached with the client, meaning that the Tab1 - which had been ok - now has a stale JSession. The next time that Tab1 sends a call, IT causes a DuplicateHTTPSession error, and the cycle repeats.
Unfortunately, the Flex framework hooks for delaying calls while sesssions are established have no easy way (that I've found) of being re-enabled once set. (I've tried the following, to no avail:)
// Reset DSid to get a new FlexSession established on LCDS
use namespace mx_internal
public function resetFlexSession()
{
FlexClient.getInstance().id = null;
// Note - using FlexClient.NULL_ID also doesn't work.
}
I feel for you - I've fought this for a long time and never found a solution, but found a fix that worked for me so hopefully it will at least keep this issue under control until you can find the culprit. (And if you do, please post it here).
Now, I've got a slightly different environment than you (I'm using CF on the backend) so keep that in mind.
I also tried the whole "FlexClient.getInstance().id = null;" thing too and it didn't work by itself, but it was how and where I implemented it that made it work.
So, this is what I did that made the problem go away.
On my main form, before ANY RemoteServer calls are made, I setup a creationComplete handler and placed this code you already know and love:
// Not sure if this is needed anymore, but I'm leaving it in
FlexClient.getInstance().id = null;
Next, in my very first call to the server, I gracefully handle the failure, and clear that stinking ID out again:
public function login(event:Event): void {
Swiz.executeServiceCall(roUsers.login(),
function (event:ResultEvent): void {
// Handle a successful login here...
}
, function (faultevent:FaultEvent): void {
// This code fixes this issue with IE tabs dying and leaving Flex with a Duplicate Session problem.
if (faultevent.fault.faultString.indexOf("duplicate")) {
FlexClient.getInstance().id = null;
Swiz.dispatchEvent(event);
}
});
}
And it worked.
Basically, try the call, and if it fails for the duplicate session thing, then clear out that ID and reissue the call.
The key point being that I don't think clearing out the ID works until you've made at least one call to the server. Once you do, it worked like a CHARM for me, and in all of my apps.
Note that I'm using the SWIZ framework above so just translate it to your own world.
By the way, I've never seen this error in any other browser but IE, and I believe it may have something to do with the infamous Dead Tab Issue that IE suffers from.
If the above doesn't work, I also know of a few changes to some config files on the server that might help.
Good luck my friend!
This article titled, Avoiding duplicate session detected errors in LCDS, gives an in-depth explanation of what's happening in your situation. Here is a relevant quote:
...[LCDS] believes that the FlexClient it received the request from was already
associated with a different session on the server.
For the client application to make sure that FlexClients in the
application don’t get into this bad state, the client application must
make sure that a session is already established on the server before
multiple FlexClients connect to the server at the same time.
There are several approaches recommended to fixing this, including:
calling a jsp page to load the application
"The jsp page could both create a session for the client application and return an html wrapper to the client which would load the swf."
calling a Remoting destination
"which would automatically create a session for the client application on the server"
An additional, unrelated, cause to be aware of;
Some browsers (Internet Explorer, for example) apply domain naming rules to cookies and this means that a code domain like "my_clientX.server.com", although it may return valid BlazeDS responses, will continually trigger duplicate session notifications as access to the cookie will be blocked.
Changing the name to a valid name (without underscore) will resolve the issue.

Is there a way using HTTP to allow the server to update the content in a client browser without client requesting for it?

It is quite easy to update the interface by sending jQuery ajax request and updating with new content. But I need something more specific.
I want to send the response to client without their having requested it and update the content when they have found something new on the server. No need to send an ajax request every time. When the server has new data it sends a response to every client.
Is there any way to do this using HTTP or some specific functionality inside the browser?
Websockets, Comet, HTTP long polling.
It has name server push (you can also find it under name Comet technology). Do search using these keywords and you will find bunch examples, tools and so on. No special protocol is required for that.
Aaah! You are trying to break the principles of the web :) You see if the web was pure MVC (model-view-controller) the 'server' could actually send messages to the client(s) and ask them to update. The issue is that the server could be load balanced and the same request could be sent to different servers. Now if you were to send a message back to the client you'll have to know who all are connected to the server. Let's say the site is quite popular and you have about 100,000 people connecting to it every day. You'll actually have to store the IPs of each of them to know where on the internet they are located and to be able to "push" them a message.
Caveats:
What if they are no longer browsing your website? You see currently there is no way to log out automatically if you close your browser. The server needs to check after a fixed timeout if you have logged out (or you send a new nonce with every response to prevent the server from doing that check)
What about a system restart/crash etc? You'd lose all the IPs that you were keeping track of and you are back to square one - you have people connected to you but until you receive new requests you can't really "send" them data when they may be expecting it as per your model.
Let's take an example of facebook's news feeds or "Most recent" link close to the top right - sometimes while you are browsing your wall you see the number next to most recent has gone up or a new 'feed' has come to the top of your wall post! It's the client sending periodic requests to the server to find out what was updated rather than the other way round
You see, it keeps it simple and restful. You may feel it's inefficient for the client to "poll" the server to pull the data and you'd prefer push, but the design of the server gets simplified :)
I suggest ajax-pulling is the best way to go - you are distributing computation to the client and keeping it simple (KIS principle :)
Of course you can get around it, the question is, is it worth it?
Hope this helps :)
RFC 6202 might be a good read.

track visitor info on every request

Using Asp.net webforms I want to track down visitor info just like Google Analytics does. Of course, I can use Google Analytic for this purpose but I want to know how can I achieve the same thing with Asp.net 3.5 and SQL Server 2008.
I want to store IP, Country, URL Referrer of the visitor, Resolution on each page request except postback. I am expecting 50k+ visit everyday..
Main concern is I want to do it in a way that it should not block current request.
i.e In general it happens when we save data in to db, current request stops on particular SP calling statment and moves ahead when it finishes executing SP or tsql statement. I want to follow "Insert and Forget" approach. It should insert in background when I pass parameter to particular event or function.
I found below alternatives for this :
1. PageAsynchTask
2. BeginExecuteNonQuery
3. Jquery Post method and Webservice (But I am not confident about this, and wondering how should I go about it)
I hope I've mentioned my problem properly.
Can anybody tell me which one is better approach? Also let me know if you've any other ideas or better approach than the listed one. Your help will be really appreciated.
Problems with any background thread in server side is each and every request is going to occupy two threads. One for serving the ASP.NET request and one for logging the stuff you want to log. So, you end up having scalability issues due to exhaustion of ASP.NET threads. And logging each and every request in database is a big no no.
Best is to just write to log files using some high performance logging library. Logging libraries are highly optimized for multi-threaded logging. They don't produce I/O calls on each and every call. Logs are stored in a memory buffer and flushed periodically. You should use EntLib or Log4net for logging.
You can use an HttpModule that intercepts each and every GET, POST and then inside the HttpModule you can check whether the Request.Url is an aspx or not. Then you can read Request.Headers["__ASYNCPOST"] and see if it's "true", which means it's an UpdatePanel async update. If all these conditions are true, you just log the request into a log file that stores the
You can get the client IP from:
HttpContext.Current.Request.UserHostAddress;
or
HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
To get the IP address of the machine and not the proxy use the following code
HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
However you cannot get the country. You will have to log the IP in your log files and then process the log files using some console application or job which will resolve the country of the IP. You need to get some IP->Country database to do the job. I have used http://www.maxmind.com/app/geoip_country before.
For screen size, you will have to rely on some javascript. Use a javascript on each page that finds the size of the screen on the client side and stores in a cookie.
var screenW = 640, screenH = 480;
if (parseInt(navigator.appVersion)>3) {
screenW = screen.width;
screenH = screen.height;
}
else if (navigator.appName == "Netscape"
&& parseInt(navigator.appVersion)==3
&& navigator.javaEnabled()
)
{
var jToolkit = java.awt.Toolkit.getDefaultToolkit();
var jScreenSize = jToolkit.getScreenSize();
screenW = jScreenSize.width;
screenH = jScreenSize.height;
}
Once you store it in a cookie (I haven't shown that code), you can read the screen dimensions from the HttpModule by using Request.Cookies and then log it in the log file.
So, this gives you solution for logging IP, screensize, finding country from IP, and filtering UpdatePanel async postback from logging.
Does this give you a complete solution to the problem?
Talking about server side, if you're running on IIS, and you don't need absolute real time information, I recommend you use IIS logs.
There is nothing faster than this, as it's been optimized for performance since IIS 1.0
You can append your own information in these logs (HttpRequest.AppendToLog), they have a standard format, there is an API if you want to do custom things with it (but you can still use text parser if you prefer), and there are a lots of free tools, for example Microsoft Log Parser which can transfer data in a SQL database (among others).
The first approach is looking good. (And I recommend it.) But it has 2 downsides:
Request will still block until task completes (or aborts on timeout).
You'll have to register your Task on every page.
The second approach looks inconvenient and might lead to errors. (You have to watch for a situation when your page renders faster than your query is processed. I'm not sure what will happen if your query is not complete when your page object is destroyed and GC goes on finalize() spree... but nothing good, I assume. You can avoid it by waiting for IAsyncResult.IsCompleted after render, but that's inconvenient.)
The third method is plain wrong. You should initiate your logging on the server side while processing the request you're going to log. But you still can call a web service from the server side. (Or a win service).
Personally, I'd like to implement logging in BeginRequest to avoid code duplication, but you need IsPostback... Still there might be a workaround.
Hii,
you can fire an asynchronous request and don't wait for response.
here i have some implemented code..
for that you need to create a web service to do your database operation or you can use it for your whole event handling.
from server side you have to call the web service asynchronously like this
Declare a Private Delegate
private delegate void ReEntryDelegate(long CaseID, string MessageText);
Now the method will contain web service calling like this
WebServiceTest.Notification service = new WebServiceTest.Notification();
IAsyncResult handle;
ReEntryDelegate objAscReEntry = new ReEntryDelegate(service.ReEntryNotifications);
handle = objAscReEntry.BeginInvoke(CaseID, MessageText, null, null);
break;
And the variable values will be passed by method here (CaseID,MessageText)
Hope this is clear to you
All the Best

Notifying the user after a long Ajax task when they might be on a different page

I have an Ajax request to a web service that typically takes 30-60 seconds to complete. In some cases it could take as long as a few minutes. During this time the user can continue working on other tasks, which means they will probably be on a different page when the task finishes.
Is there a way to tell that the original request has been completed? The only thing that comes to mind is to:
wrap the web service with a web service of my own
use my web service to set a flag somewhere
check for that flag in subsequent page requests
Any better ways to do it? I am using jQuery and ASP.Net, if it matters.
You could add another method to your web service that allows you to check the status of a previous request. Then you can use ajax to poll the web service every 30 seconds or so. You can store the request id or whatever in Session so your ajax call knows what request ID to poll no matter what page you're on.
I would say you'd have to poll once in a while to see if request has ended and show some notifications, like this site does with badges for example.
At first make your request return immediately with something like "Started processing...". Then use a different request to poll for the result. It is not good neither for the server nor the client's browser to have long open HTTP sessions. Moreover the user should be informed and educated that he is starting a request that could take some time to complete.
To display the result you could have a"notification area" in all of your web pages. Alternatively you could have a dedicated page for this and instruct the user to navigate there. As others have suggested you could use polling to get the result.
You could use frames on your site, and perform all your long AJAX requests in an invisible frame. Frames add a certain level of pain to development, but might be the answer to your problems.
The only other way I could think of doing it is to actually load the other pages via an AJAX request, such that there are no real page reloads - this would mean that the AJAX requests aren't interrupted, but may cause issues with breaking browser functionality (back/forward, bookmarking, etc).
Since web development is stateless (you can't set a trigger/event on a server to update the client), the viable strategy is to setup up a status function that you can intermittently call using a javascript timer to check whether your code has finished executing. When it finishes, you can update your view.

Resources