Why does Application_BeginRequest() fire twice when refreshing browser? - asp.net

I'm observing some really confusing behavior with the Application_BeginRequest event in my Global.asax file (in an ASP.NET MVC app). When running through the debugger, if I Refresh my browser (IE7), this event fires twice. If I click a link or otherwise manually request a page, it fires once - as expected.
Why does a refresh cause BeginRequest to fire twice?
I'm observing this with a brand new MVC project with the following addeded to Global.asax.cs
protected void Application_BeginRequest() {
//executed twice
}
For context, I'm trying to add a new object to the HttpContext.Current.Items collection during this event, so it will persist through the entire request process. Obviously, I don't want this to happen twice for a single refreshed request!

Are you sure it's really 2 request to the same URL? I would think that the second is probably some dynamic JS, CSS or image file. Try to find out either with Fiddler or by looking at HttpContext.Current.Request.Uri in the debugger

Something that surprised me a while back was that if you have an img tag in your html that doesn't have a proper image path, some browsers will make a request to the original page. Here is a related blog post.

I'm not sure why this is occuring but I find it's easier to create a BaseController class and have all my controllers inherit from it. Alter the constructor to add your item to the HttpContext.

Do you have a reference in your HTML to something that also passes the ASP.NET pipeline, like a dynamically generated image or something like that?

Related

Force the ASP.NET page lifecycle to go forward

Ok, so I am working on a custom framework above the .NET framework, and some instructions are not written / called at the good places.
For example, a postback is done on the same page. Then, a Response.redirect occurs right within the page_load; but at this point, the new values of the controls of the page are not yet handled, so they get lost...
Therefore, I wanted to know whether it was possible to force the pagelife_cycle to go forward before the call to response.redirect, so that I can get the right values.
I can't just make that call in another function, because the page I am working on is called by many web applications (about 1-2k), and it would completely change their behaviour, which is not acceptable!
Is that even possible?
See a bit the second image and the Load PostBack Data section. Before the Load event of the page is raised, a textbox is already initialized. You can catch the value by overriding OnPreLoad or by adding a handler at PreLoad event.

Track # of page viewed in a session in asp.net

I am currently working on a project where I want to implement a bit of logic for each .aspx viewed.
My idea was to use an httphandler that will target *.aspx, and in the handler, I would do my bit of logic, such as printing out: This is the xth page you have visited in this session.
I am curious if there are any problems with my idea or is there a more proper solution I am not aware of.
Though I have tried implementing my solution, I run into an infinite loop. After I complete my logic with the handler, I redirect to the same page, but that of course calls the same handler. Is there a way to bypass the handler on the redirect or a specific way to execute the same page without accessing the handler.
Thanks for the help!
~
Are you using a master page? If so, you could simply increase the count of your session variable in the master page's load event and display or write to DB anytime thereafter.
I think possibly you mean an HttpModule - a handler is an endpoint, you wouldn't have much of a page to display as well.
I would have suggested you add such a counter to a root master page. Simple to implement, doesn't have pipeline complications, can encapsulate the output control a well as the logic behind it.
Your handler shouldn't redirect...
Create an HttpModule and put this in the request pipeline. That way your code will execute and add the info you want while letting the page itself execute as necessary.
Or you could just take Matt's idea and put this in the master page. You'll have more control over where your text goes that way AND it's way simpler to implement.
You should do this with an IHttpModule instead. Modules are executed once per request, and their purpose is to something that does not have to do with the rendering of a page, unlike a handler.

In ASP.Net, How do I run code after sending page

In ASP.Net, I want to run some code (logging, other cleanup) after the page has already been sent to the user. I don't want this code to interfere with the amount of time it takes the client to receive a response. I tried placing this code in the OnUnload part of the page, but through testing (using breakpoints, or busy waiting loops) the client does not actually display the page until the code in the OnUnload is finished executing. Even though the response object is no longer available at this point, and therefore I would assume that the buffered response has been sent to the client, the client still does not display the page until the OnUnload is finished executing. The only way that seems to work at the moment is to start a new thread to do the work, and allow the OnUnload to finish immediately. However, I don't know if this is safe or not. Will the server kill the thread if it executes too long after the page is already sent out? Is there a more correct way to accomplish this?
Kibbee,
Try overriding the Page.Render method and flushing the response like so:
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.Render(writer)
Response.Flush() ' Sends all buffered output to the client
' Run some code after user gets their content
End Sub
I think at this point the response still isn't complete, but the user will get what the page has rendered before you finish running that final code.
HTH,
Mike
Unload is the last part of the ASP.NET page life cycle. See link below:
http://msdn.microsoft.com/en-us/library/ms178472.aspx
Is this something you could do with javascript or AJAX?
How about hooking into the page.Disposed event instead of the Unload event?
Depending on what you need to do an ISAPI filter can be created to do stuff at the end of the response.
You could try this solution - Best ASP.NET Background Service Implementation
Using a windows service and communicating with it through MSMQ might be a far more reliable solution and can scale up better. This will help you separate the concerns and let asp.net front end just focus on the user while the windows service focusses on the background tasks.
If you are moving to the cloud with azure, you can simply replace the asp.net front end with a web role and the windows service with a worker role and ur solution can scale seamlessly!
Here's a redneck way to do it. Have a second aspx page that does all your "clean up" post-rendering logic. Call that one 'cleanup.aspx' for example. Have your clean up code run in Page_Load of cleanup.aspx:
public partial class cleanup: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// do logging blah blah here....
}
}
In your main aspx page, have a JavaScript function that makes an AJAX call to 'cleanup.aspx'. Make the AJAX function fire after page load. I recommend jquery, if so your code will look like this:
$(function(){
yourAJAXYFunctionName();
});
function yourAJAXYFunctionName()() {
// ajax code here
//
$.ajax({
url: "cleanup.aspx",
});
}
This way, your first page's code runs, then the page is sent to the browser. As the page renders to the client, the 2nd ASPX page is called via AJAX, which really doesn't matter to cleanup.aspx, it doesn't care how its called and its page load event is executed. Your cleanup/logging code is then ran.
Caveats: client side JavaScript is required. But really who the hell doesn't have JS running anyway? Also, your cleanup.aspx page is totally abstracted from your main page, so if you want to use any object in cleanup.aspx that originated in your first page, then you'll have to store them in session or cookies, or you can pass them as parameters in the AJAX call. That will require dynamic manipulation of the AJAX script itself, but that's not too hard.
Better i think try try{Response.End()}catch{} runcode();

Javascript window.onunload fires off after Page_Load

I have noticed that window.onunload event fires off AFTER page_load event which makes no sense.
This behaviour is creating an issue for me - in my unonload I clear the session, so if the Page_Load first BEFORE onunload, there are errors on the page displayed.
I would expect the javascript onunload to fire BEFORE Page_Load....is that the correct assumption?
TO CLARIFY:
Let's assume I am on page test.aspx, then I click on the link that goes to the same page (say I click on a menu), what I observe is that Page_Load fires first, then onunload fires off.
Makes no sense at all.
It's a browser-specific behaviour. Chrome and FF will send a GET requst BEFORE onunload is fired, IE8 will execute onunload first. Not sure, how the other browser handle it. Better not rely on this functionality.
Have you considered using a common base class for your pages, and clearing the session in there if the request isn't a postback (I assume that you're using session for postbacks)?
public class BasePage : System.Web.UI.WebControls.Page {
protected override OnPreInit (EventArgs e) {
// Get in nice and early, however you could use OnInit if you prefer
if (!Page.IsPostBack) {
Session.Clear();
}
}
Then your pages that need to clear session can be declared as:
public class SpecialPage : BasePage {
// Your page logic goes here.
// Note that if you need to do work in OnPreInit here you should call
// base.OnPreInit(e) first.
}
I would guess that window.unload is actually firing only when you're going to have to RENDER the new page you navigated to (aka the old DOM is being torn down in place of some new HTML). The browser doesn't know what to render until the response comes back from the server with the HTML to display. That HTML isn't generated until the page lifecycle completes, which includes Page_Load. Hence the page_load before the window.unload?
In any case, if you can clear the session during window.unload, why not just clear it in response to some user interaction and be a bit more explicit about it?
Edit: Could you also try window.onbeforeunload?
The onunload event does fire before the request for the new page is fired off to the server, so it definitely fires before the Page_Load method runs on the server.
The problem is most likely that you are sending another request to the server from the onunload event. As the IIS only handles one request at a time from each user, this request will be queued and executed after the request for the new page.
You can write an utility function which will handle removing of the session variables and then call that function in the respective menu click events. That should be simpler to use since window unload will fire after page load only.
It sounds like you are using the Session to save temporary variables that change from page to page. I would say the Session is not really suitable for this kind of scenario. A better solution would be to use the Httpcontext's Item collection which is scoped only on a per request basis. It's works just the same as the Session when storing data.
Context.Items["myvariable"] = "some data";
As it's only scoped on a per request basis, there is no need to use javascript to clear the items you have stored on each page request.

How to Track F5/Refresh in ASP.Net

I am using VS 2005, C# 2, ASP.Net 2.0
I am unable to find out how to track that user pressed F5/Ctrl+F5/ Open a new Window(Ctrl + N) in ASP.Net.
I know that there is a Page.IsPostBack property, which tells that a page is loaded in response to an action taken by user.
I am just curious to know, that why isn't there a property as IsRefresh or Page.IsRefresh in ASP.Net, which will return true,
whenever user takes any of the above actions.
Is there a way to know this?
Actually my problem is that i have a DLL using which all of my aspx pages are inherited, I have to
insert some values in a table whenever the page is opened for the first time that's it, if user just opens the page or do not take any action,
an entry should be inserted into the database, but as far as I have tried, I controlled it anyhow using the Page.IsPostBack property, but I got stuck
in the refresh case, as it is inserting records unconditionally.
Similar to using a function in Global.asax (as others have suggested) you could use a session variable "flag". When the page first loads set a session variable and then just check against it in your page load function:
if (Session("visited") != "true"
//page has not been visited, log visit to DB
Just make sure you set the session flag sometime after the above check during the page load.
It won't be exact (sessions can timeout while a page is active, users can completely leave the site and come back in the same browser and the session stays alive, etc) but for your tracking it is much better than counting every page hit in the DB.
Perhaps you want the Session_Start method in the Global.asax file, which will be triggered once at the start of each user session?
In your Global.asax file, add or edit the method:
void Session_Start(object sender, EventArgs e)
{
}
why isn't there a property as IsRefresh or Page.IsRefresh in ASP.Net
Because ASP.NET cannot possibly know. The browser does not send any information that could allow it to determine whether the page is being requested due to a refresh or normal load. You will need to reconsider your requirements: what is the actual purpose of the database logging?
Session_Start method in Global.asax file is fired every time when a browser session is started. You can use this method to count number of unique users on your website.
Session_End method in Global.asax is fired when a session ends (explicitly or timedout). So you can decrement the count here.
Hope the above to example uses of these methods helps you understand how you can use them.
Because of the stateless nature of HTTP protocol there is no way to tell apart the initial load from the refresh
As has already been said. This isn't possible. A request issued due to a refresh is no different to a request issued the first time the page is loaded.
It sounds to me like you are trying to track page views somehow. This is certainly possible though it will require some work on your part. Your best bet is probably to log the URL of the page. You may also want to include the query string in order to differentiate between page loads for different pieces of data (if this happens in your application). You will also want to log the ID of the current user, and the ID of their session.
You can then make sure that you don't insert two page views for the same user for the same page in the same session, effectively filtering out any reloads of a page.
You do need to be aware that this isn't the same as detecting a refresh, what you are detecting is two page views in the same session, this could be a refresh, or it could be use of the back button, or just reloading from the address bar.
My suggestion would be to create a cookie on very first load, then on Page_Load check to see if the cookie exists. If it does, don't insert the record. You can use Session_End to destroy or create the cookie as someone suggested if that works with your application's architecture.

Resources