Javascript window.onunload fires off after Page_Load - asp.net

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.

Related

Change textbox value from event handler for object in codebehind page

I have an object, let's call it objK that has an event Message that accepts a string. I have a event handler in my code behind page called HandleObjKMessage(string s). that method looks like this currently :
void HandleObjKMessage(string s)
{
TextBox1.ReadOnly = false;
TextBox1.Text += s+ Environment.NewLine;
UpdateP.Update();
}
objK is an object from an external .dll(assembly) that is running an iterative process that I need to be keeping the user update from. That is the purpose of using an event.
Am i barking up the wrong tree? I'm typically a winforms guy and this is frustrating the hell out of me.
Thanks.
I might have misunderstood you, but you have an object that you instantiate, and then add an event handler to this object's event, and when the event fires you want the user to get the updated data?
If this is the case, it is not possible. This is simply because the web does not have state. There is no persistent connection between the server and the client.
When a request is received for your page, the server will create an instance of your page class, and run through the life-cycle (init, load etc.) Once the page has been rendered into HTML markup, the server disposes the instance of the page, and thus your attached event handler.
You can read more about the WebForms Page Lifecycle at MSDN
If you really want to go all the way and actually push the notification to your user, you could use SignalR, but this adds quite some complexity.

reload current page in asp.net

I have a session variable that changes some things about how a page looks. I have a button that changes the value of this session variable. But ... the onClick event happens after page load, so by the time I update the session variable based on the button click, it's too late, the page has already been loaded.
Theoretically I could put all the logic about changing the display into a function and call it from page load, and then call it again from the onclick after the variable as been updated. But this is impractical: there are many user controls that check the value, used on many different pages in different combinations. I would have to hard-code the list of user controls on each page, and if someone added a new user control to a particular page, they'd have to remember to update this function, which is lame.
Is there a way to force a page reload? (I can use response.redirect back to myself and it works. If all else fails I guess this is what I'll do. But it means an extra round trip to the server, which is clumsy.)
Is there a way to process the onclick before the page load?
Some other magic solution?
If you have to change the look and feel of a page based on a specific value which can change, then you should have dedicated functions that set up the look and feel in a single unified place, and then you call those functions in every case where a value that affects the look and feel is called.
Examples:
private void SetDivVisibility()
{
// display logic here based on variables
}
private void MyControl_Click(...)
{
myvalue = blah;
SetDivVisibility();
}
It helps to bear in mind that the actual rendering of the page is last thing that happens, after both page load AND event processing.
Theoretically I could put all the logic about changing the display into a function and call it from page load
That's how you should do it. Cleanup your logic and markup - refactor and keep it DRY. That should help.
I can use response.redirect back to myself
That's the other option. Yes, a round trip is nasty.
you may put your code of styling your page in a void called by the page_load normally and called again from buttonclick
or call response.redirect to same url
or even onClick is client side use window.location.href
A design with a layout predicated on the existence of a session variable which won't exist until after it's been render is a huge design error. I like to call it the "Chicken or the Egg" syndrome. (yes, you can quote me.. ;)
I'd argue that your controls shouldn't get their layout completed in the on render. Instead, use a method (similar to databinding) where you can "rebind" the controls with the new session value on demand. This method would show/hide things based on the updated values.

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();

Why does Application_BeginRequest() fire twice when refreshing browser?

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?

How do you call a Javascript function from an ASPX control event?

How do you call a Javascript function from an ASPX control event?
Specifically, I want to call the function from the SelectedIndexChanged event of a DropDownList.
I get a little nervous whenever I see this kind of question, because nine times out of ten it means the asker doesn't really understand what's going on.
When your SelectedIndexChanged event fires on the server, it fires as part of a full postback. That means that for that code to run, the entire rest of your page's load code also had to run.
More than that, the code runs as the result of a new http request from the browser. As far as the browser is concerned, an entirely new page is coming back in the result. The old page, and the old DOM, are discarded. So at the time your SelectedIndexChanged event code is running, the javascript function you want to call doesn't even exist in the browser.
So what to do instead? You have a few options:
Change the page so the control doesn't post back to the server at all. Detect the change entirely in javascript at the client. This is my preferred option because it avoids odd onload scripts in the browser page and it saves work for your server. The down side is that it makes your page dependent on javascript, but that's not really a big deal because if javascript is disabled this was doomed from the beginning.
Set your desired javascript to run onload in the SelectedIndexChanged event using the ClientScript.SetStartupScript().
Apply the expected results of your javascript to the server-model of the page. This has the advantage of working even when javascript is turned off (accessibility), but at the cost of doing much more work on the server, spending more time reasoning about the logical state of your page, and possibly needing to duplicate client-side and server-side logic. Also, this event depends on javascript anyway: if javascript is disabled it won't fire.
Some combination of the first and third options are also possible, such that it uses javascript locally if available, but posts back to the server if not. Personally I'd like to see better, more intuitive, support for that built into ASP.Net. But again: I'm talking about the general case. This specific event requires javascript to work at all.
As Muerte said you have to just put the javascript, or a call to it on the page from the code behind. Personally I use this:
ClientScript.RegisterClientScriptBlock("customscript", "<script>simple script here</script>")
Of you can call the function if you already have a more complex one on the page instead of the stuff I have.
You can't do it directly from an event, because ASPX control event is server side.
What you can do is emit a Javascript in the ASPX event which will call the JavaScript function when the page reloads.
For example, if in your ASPX page you have a Javascript function called "DoSomething()", in you ASPX control event, add the following:
protected void btnSubmit_Click(object sender, EventArgs e)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "myEvent", "DoSomething()", true);
}
The last boolean parameter defines that tags are added automatically.
In the code behind, attach some markup to the server side control via its attributes collection. This assumes that the function is already in a client script file that is already available to the page.
MyServerDDLControl.Attributes.Add("SelectedIndexChanged", "MyClientSideFunction();");

Resources