I’ve been asked if we can optionally “single-instance” our web portal. See
this post on Hanselman's blog for the same idea in a WinForms app.
Suppose we have 2 shortcuts on the same client machine:
http://MyServer/MyWebPortal/Default.aspx?user=username&document=Foo
http://MyServer/MyWebPortal/Default.aspx?user=username&document=Bar
Clicking on the first shortcut would launch our web portal, log in, and display the document “Foo”. Clicking on the second shortcut should display the document “Bar” in the running instance of the web portal.
My current approach is this: In the Page Load, for the first instance create a per-client Application variable. The second instance looks for the Application variable to see if the portal is running on the client. If it is, the second URL is recorded in another Application variable and the second instance is forcibly exited. I’ve tried creating a ASP.Net AJAX Timer to poll the Application variable for a document to display. This sort of works. In order to respond quickly to the second request I’ve set the Timer interval to 2 seconds. This makes the portal irritating to use because of the frequent postbacks.
Using my approach, is there a way for the second instance to notify the first instance to check the application variable without polling? Is there a better overall approach to this problem?
Thanks in advance
There is no way on the server side to control which browser instance your page opens up on the client. You can't force all requests to open in the same browser window.
Also, an Application scope variable is shared by all users of your application. At least make this a Session-scope variable - otherwise you would only be allowing one user to access your portal at a time!
Honestly this sounds like a silly request from someone who a) probably doesn't understand how these types of things work and b) is trying to do an end-around for users who aren't that bright and actually see a problem with having more than one instance of your portal open.
Related
I had to update an old ASP+COM application for a customer when they went from Windows 2003 to 2008R2. The process, while not 100% painless, was sucessful but one problem remains: the application seems to randomly lose the session state or, at least, the session variable where I save the session's COM object.
Basically, the app works like this:
Login form page -> login page (object is created there and saved in Session("MyObject"), user credentials are checked -> First actual application page (Session("MyObject") is checked at the top of the code).
The Second redirect only happens if the credentials are correct but the object is always created.
However, users are reporting that they are frequently being redirected to the logon form page after entering their credentials.
After some investigation, it seems that the application properly goes through the login page, creates and instance of the COM object and redirect to the first application page. And there, the session variable is empty again and so the user is sent back to the login form.
What's more is that it is by far not systematic: the problem happens rather frequently but definitely not all the time. When it starts, users have to log on 2 or 3 times before they can get through. If the application is recycled, it usually solves the issue for some times although this isn't systematic and this isn't even always necessary.
Anyone has any idea what could be going on here ?
Edit: some extra info:
ASP session handling is active
In no part of the code are errors being silently suppressed. They will go to a log file if they happen somewhere the COM object can catch them or the user otherwise.
No error can be seen in the COM object log file, in the IIS log or in the server's event log.
Tracing the process activity with ProcMon didn't turn up anything special.
Looking at the COM object log file, I clearly see the COM object instance being created, the "LoginUser" method being called from the login page and returning successfully and then the first application page being called and the check for the existence of the object stored in the session failing.
There is a single web server, no server farm.
I did have an asp website that did exactly the same thing in the past. You need to check the log files and see if this application or website is running on it's own dedicated application pool and that the application pool is not being auto recycled due to bad code. If the session is being created then dropped, then pass the initital session value to another session - say Session("MyObject2") and check for that in the main page. If the users are still getting logged off then I am sure that the application pool is being recycled due to too many failures such as a redirect infinite loop or something else.
Edit: One more thing. I used to see such errors a lot when using ASP with MS Access and could never figure that out.
As a debugging exercise, I'd be tempted to log info from the ASP Session events including the session OnStart, OnEnd and abandon. Maybe try and get as much info from the request and then work out a given lifecycle/page flow for sessions and then determine if there is anything in common that occurs when the session is either ended or abandoned.
Also, while looking up the Session_OnEnd event, I came across an article that suggests it behaves weirdly in IIS 7.0 See http://blogs.iis.net/lprete/archive/2009/01/04/session-onend-classic-asp-and-iis-7-0.aspx just in case this might be of use.
Good luck.
I was wondering if there is any way to always run some server side code when a user leaves a page in ASP.NET. The page Unload event is no good because that doesn't get called if someone clicks on a link. Ideally I'd also like the code to run even if the user closes the browser.
I suspect what I'm asking isn't possible, but it doesn't hurt to ask
Problem is, HTTP is a stateless protocol, so when the page has finished being served, you wont know if the user is still on the page or not.
The only way to acheive this would be a hidden piece of Javascript that constantly pings the server with it's session ID, or another similar mechanism. When the ping becomes unresponsive you can reasonably assume the page is not being viewed by the user anymore.
Here is a diagram that explains traditional HTTP message flow.
im not really sure if you can do that but i have a workaround in mind.
There is an event in the DOM called onbeforeunload. it get calls everytime a user leaves a page. you can try sending an ajax request to the server from this function.
The closest thing you can come without creating too messy a solution is to enable ASP sessions. This will create a session on the server for each visitor, who will be identified by a cookie.
After a certain amount of inactivity from the visitor, the session will be closed, and a SessionEnd event will be raised. This you can hook up to in the Global.asax file.
I will not recommend this however, because HTTP is pr. definition a session-less protocol, and using server based sessions violates this fact, and are often problematic. Many solutions that use server based sessions run into problems when the user uses the browser-back button, and resubmits a form. Because the content of the submitted form no longer corresponds the data that exists in the server session.
Also, enabling server based sessions seriously hurts the scalability of the application.
Not that I know of. You'll need to use javascript for that, and call a web service on the server side.
Say, for example, you are caching data within your ASP.NET web app that isn't often updated. You have another process running outside of the app which ocassionally updates this data, when you do this you would like the cached data to be cleared immediately so that the next request picks up the new data straight away.
The caching service is running in the context of your web app and not externally - what is a good method of calling into the web app to get it to update the cache?
You could of course, just hack a page or web service together called ClearTheCache that does it. This can then be called by your other process. Of course you don't want this process to be externally useable or visible on your web app, so perhaps you could then check that incoming requests to this page are calling localhost, if not throw a 404. Is this acceptable? Could this be spoofed at all (for instance if you used HttpApplication.Request.Url.Host)?
I can think of many different ways to go about this, mainly revolving around creating a page or web service and limiting requests to it somehow, but I'm not sure any are particularly elegant. Neither do I like the idea of the web app routinely polling out to another service to check if it needs to execute something, I'd really like a PUSH solution.
Note: The caching scenario is just an example, I could use out-of-process caching here if needed. The question is really concentrating on invoking code, for any given reason, within a web app externally but in a controlled context.
Don't worry about the limiting to localhost, you may want to push from a different server in future. Instead share a key (asymmetrical or symmetrical doesn't really matter) between the two, have the PUSH service encrypt a block of data (control data for example) and have the receiver decrypt. If the block decrypts correctly and the data is readable you can safely assume that only the service that was supposed to call you has and you can perform the required actions! Not the neatest solution, but allows you to scale beyond a single server.
EDIT
Having said that an asymmetrical key would be better, have the PUSH service hold the private part and the website the public part.
EDIT 2
Have the PUSH service put the date/time it generated the cipher text into the data block, then the client can be sure that a replay attack hasn't taken place by ensuring the date/time is within an acceptable time period (say a minute).
Consider an external caching mechanism like EL's caching block, which would be available to both the web and the service, or a file to cache data to.
HTH.
I have a user control in my page which is inside a update panel.By using the user control i am displaying a message for the user.I need to change the message every 5 min.The message is stored in the data base and the user control will retrieve the message from the database every 5 min once automatically.
My problem is when there are more than 50 users accessing the same page then for every 5 min the request is sent from each client automatically to the server which decreases the server performance.
So can anybody help me to resolve this performance issue.
Make use of the Cache object in the UI tier to load in the different texts. Only load it in on first request when needed.
have a user control in my page which is inside a update panel
Try to get rid of the updatepanel as it will always send back and forth the full viewstate of the page. Make use of ajax, script only instead in combination with a PageMethod or a service endpoint (.asmx or wcf).
Also measure where things are going slow. I like to use tools like YSlow and Sql Profiler to measure. ASP.NET also has the capability of tracing which you can turn on/off in the web.config.
Requests to server will always use up resources. It's a fact of life.
You don't say which server it is that has the performance problem, but if the message in the database is static, then why not load it into a cache on the application server so that each client doesn't make a request to the database?
You need to profile your application to find the performance bottleneck(s).
Seriously! Anything else is just guessing.
Even though it did not top the list, I recommend the EQATEC Profiler.
Update
Just thought I would point out that 50 concurrent users should be no problem for ASP.NET.
MySpace runs on ASP.NET with 2.3 million concurrent users and handles 1.5 billion page views every day.
I am not able to make more than one request at a time in asp.net while the session is active. Why does this limitation exist? Is there a way to work around it?
This issue can be demonstrated with a WebForms app with just 3 simple aspx pages (although the limitation still applies in asp.net mvc).
Create an asp.net 3.5 web application.
There should be just three pages:
NoWait.aspx, Wait.aspx, and SessionStart.aspx
NoWait.aspx has this single nugget added between the default div tags: <%=DateTime.Now.Ticks %>. The code-behind for this page is the default (empty).
Wait.aspx looks just like NoWait.aspx, but it has one line added to Page_Load in the code-behind: Thread.Sleep(3000); //wait 3 seconds
SessionStart.aspx also looks just like NoWait.aspx, but it has this single line in its code-behind: Session["Whatever"] = "Anything";
Open a browser and go to NoWait.aspx. It properly shows a number in the response, such as: "633937963004391610". Keep refreshing and it keeps changing the number. Great so far! Create a new tab in the same browser and go to Wait.aspx. It sits for 3 seconds, then writes the number to the response. Great so far! No, try this: Go to Wait.aspx and while it's spinning, quickly tab over to NoWait.aspx and refresh. Even while Wait.aspx is sleeping, NoWait.aspx WILL provide a response. Great so far. You can continue to refresh NoWait.aspx while Wait.aspx is spinning, and the server happily sends a response each time. This is the behavior I expect.
Now is where it gets weird.
In a 3rd tab, in the same browser, visit SessionStart.aspx. Next, tab over to Wait.aspx and refresh. While it's spinning, tab over to NoWait.aspx and refresh. NoWait.aspx will NOT send a response until Wait.aspx is done running!
This proves that while a session is active, you can't make concurrent requests with the same user. Requests are all queued up and served synchronously. I do not expect or understand this behavior. I have tested this on Visual Studio 2008's built in web server, and also IIS 7 and IIS 7.5.
So I have a few questions:
1) Am I correct that there is indeed a limitation here, or is my test above invalid because I am doing something wrong?
2) Is there a way to work around this limitation? In my web app, certain things take a long time to execute, and I would like users to be able to do things in other tabs while they wait of a big request to complete. Can I somehow configure the session to allow "dirty reads"? This could prevent it from being locked during the request?
3) Why does this limitation exist? I would like to gain a good understanding of why this limitation is necessary. I think I'd be a better developer if I knew!
Here is a link talking about session state and locking. It does perform and exclusive lock.
The easiest way around this is to make the long running tasks asynchronous. You can make the long running tasks run on a separate thread, or use and asynchronous delegate and return a response to the browser immediately. The client side page can send requests to the server to check and see if it is done (through ajax most likely), and when the server tells the client it's finished, notify the user. That way although the server requests have to be handled one at a time by the server, it doesn't look like that to the user.
This does have it's own set of problems, and you'll have to make sure that account for the HTTP context closing as that will dispose certain functionality in the asp.net session. One example you'll probably have to account for is probably releasing a lock on the session, if that is actually occurring.
This isn't too surprising that this could be a limitation. Each browser would have it's own session, before the advent of ajax, post back requests were synchronous. Making the same session handle concurrent could get really ugly, and I can see how that wouldn't be a priority for the IIS and ASP.NET teams to add in.
For reasons Kevin described, users can't access two pages that might write to their session state at the same time - the framework itself can't exert fine-grained control over the locking of the session store, so it has to lock it for entire requests.
To work around this, pages that only read session data can declare that they do so. ASP.NET won't obtain a session state write lock for them:
// Or false if it doesn't need access to session state at all
EnableSessionState="ReadOnly"