ASP.Net's auto-postback. What happens when its too slow? - c#

I am making a web application. I have gotten a weird error with update panels.
Ok, so say you have two update panels and each update panel has a textbox in it. Both of these textboxes are auto-postback and the update panels update conditionally.
Well, from the behavior I'm observing it seems like if the server isn't faster than the user at processing a request then it sorta gets ignored on the client side.
Like say you type something in 1 of these text boxes and then quickly tab to the next one and type something and tab out. This should cause 2 post backs.
Well, what if 1 post back is being processed at the server and another one happens? Does that post back get dropped at the server side or client side?
The main problem I'm observing with this situation is that when a post back occurs the 1st time, there is a Update() for an update panel. Well, when the 2nd post back occurs interrupting the first, it also does an Update on an update panel(a different one). What the user sees is if they tab through it very quickly(or the server is under high load or whatever) then the 2nd update panel gets updated but not the first.
tl;dr: When a post back interrupts another post back, any update panels that were suppose to be updated in the first post back are not updated(though the second postback ones are)
How can I work around this problem or solve it? I can not update all of the update panels on the screen because then the control that the user is currently on loses focus along with a whole lot of other problems.

UpdatePanels intercept the postback and make a request back to the server using the XMLHTTPRequest object (i.e. they use AJAX).
The second XMLHTTPRequest will cancel the first one if it is still in progress when the second one is made. This is standard behaviour as far as I am aware.
You might want to have the UpdatePanels update together on a button click as opposed to having the update attached to an event on each textbox (it sounds like you have them attached to the blur event). This way you can ensure that lots of requests aren't being made and perhaps disable the button whilst a request is in progress, to prevent a new request from cancelling the one in progress.
EDIT:
You can prevent another request being made form the client side while one request is already in progress by checking the PageRequestManager's isInAsyncPostBack property. Something like the following
function pageLoad(sender, args) {
var pageManager = Sys.WebForms.PageRequestManager.getInstance();
// add a function to execute when an asynchronous postback is initialized
pageManager.add_initializeRequest(checkAsyncPostback);
}
function checkAsyncPostback(sender, arg)
{
var pageManager = Sys.WebForms.PageRequestManager.getInstance();
// check if an async postback is already in progress
if (pageManager.get_isInAsyncPostBack()) {
// cancel this async postback if one is currently in progress
arg.set_cancel(true);
}
}
There isn't really an easy way to know from the server side if the postback is interrupted.

I can't answer your questions specifically, because I don't know how the page manages UpdatePanels and their requests/responses. But, you can probably very easily tell what's going on if you trace the calls with Fiddler. You can see when the requests are firing, and you can see the response as well as if an HTTP error code is sent back or an exception is thrown, etc:
Fiddler2

Look at using the UpdateProgress control: http://www.asp.net/ajax/documentation/live/overview/UpdateProgressOverview.aspx
Also, UpdatePanels are overkill for this kind of thing. Look at using Page Methods (google ASP.NET Page Methods)
EDIT: To further clarify how this would be useful to you, modify the contents of the ProgressTemplate in the UpdateProgress control to display in a modal fashion, so that users cannot do anything until the request completes.

Related

When exactly do Page.RegisterAsyncTask's get called?

I am running into confusing behavior related to async code registered on an ASP.NET page with RegisterAsyncTask, ViewState, and checkboxes, and I need to know exactly when these async-tasks run relative to when ViewState is saved.
I have a few checkboxes inside an ASP:PlaceHolder control. I am reading a record and populating the checkboxes, then I make the PlaceHolder visible.
If all this is synchronous - maybe within Page_Load - all is well.
If this is registered as an async task the following happens:
The checkboxes get populated.
The Placeholder is visible.
On postback, checkboxes cannot be UNCHECKED. That is, if they were initially checked they retain their checked status even if the user unchecked them. It seems like the checkboxes revert back to their initial values. If a checkbox is checked on the client, that makes it! Unchecking doesn't.
This doesn't seem to be a problem with textboxes. I haven't tried other widgets.
I can 'correct' this problem by setting the PlaceHolder to be visible BEFORE I register the async task. I think this is similar to my other question about Grid visiblity:
asp:DataGrid visibility with async?
It's turning out to be very difficult and resulting in confusing code as I try to pull all the visiblity-rules out of async methods.
I see from the ASP.NET page lifecycle that gets saved sometime before OnPreRender. I also think RegisterAsyncTask'd code gets run about the same time. What order does this happen in? If ViewState is saved before my code runs I'm sunk!
Edit: I found some more detail but it is still confusing:
Halfway down this page: http://www.asp.net/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45 it says
"Methods hooked up with RegisterAsyncTask will run immediately after PreRender."
This page: https://msdn.microsoft.com/en-us/library/ms178472(v=vs.85).aspx details the PreRender and SaveStateComplete events but doesn't mention RegisterAsyncTask. I need to experiment to see if its shoe-horned between them.
The ExecuteRegisteredAsyncTasks gives you some more control in when the tasks are being started.
The ExecuteRegisteredAsyncTasks method is automatically called at the
point in the page processing when any registered asynchronous tasks,
if they exist, are invoked for a non-asynchronous page. This automatic
call to ExecuteRegisteredAsyncTasks occurs just before the
PreRenderComplete event.
From PreRenderComplete documentation:
This is the last event raised before the page's view state is saved.

How long am I supposed to wait to do something after I call WebBrowser.Refresh?

I have a web page that I am tearing elements out of for use in a program I am writing. It takes a moment for a particular element to load into the web page, so I thought I would use WebBrowser.Refresh() in order to accomplish getting the up to date code.
Unfortunately doing so causes a whole lot of headache if you want to do ANYTHING afterwards since it doesn't fire the DocumentCompleted event (before anyone asks, it even says that explicitly on the MSDN).
So I need a method to allow the program like 2 seconds of doing nothing after it refreshes the page. The problem is that I don't know how to do that and be able to get the updated WebBrowser.Document. If I use Thread.Sleep, the entire application hangs while it sleeps and nothing gets updated.
And if I immediately try, I invariable get the crappy crappy problem of the WebBrowser object hanging forever or throwing Null Cast exceptions.
Has anyone else had this sort of problem (or something similar) and found a solution?
Why don't you just navigate to the URL again?
webBrowser1.Navigate(webBrowser1.Url);
This will fire the event handlers that you need.
I had a similar problem in getting a WebBrowser to refresh at a desired time. As you are discovering, it is hopeless to try to get it to refresh on demand; the HTTP response and HTML rendering are both non-deterministic.
My advice is to attach to the DocumentCompleted event of the WebBrowser, call the desired web page early in the background and show the user something to distract them, then show the completed WebBrowser after DocumentCompleted fires.
If you want to be lazy and not use background threads:
wb.Refresh();
while ((wb.ReadyState != WebBrowserReadyState.Complete)) {
Application.DoEvents();
}
//Refresh is now complete
ReadyState should only be WebBrowserReadyState.Complete once all Ajax and content has completed loading.

Silverlight Application UI updating

Hi I have a problem when I am working on my Windows Phone silverlight C# application.
So I want to do something like this
Press a button on page one. The button click handler calls a async method MakeRequest in other class to retrieve data. The async method will fire a event DataReadyEvent and has the result wrapped as DataEventArgs.The handler of this event will be in Page2. So after add a handler to this event, I navigate to Page2 from current page.
I want to retrieve data by a event handler in Page 2 code behind and update that on UI. But the event handler is static (so that I can add it by using Page2.handler_method_name in page1 code without creating a new instance of the page.). Since the handler method is static, I cannot use Dispatcher.Invoke and get back to the UI thread and update UI.
So in this case, anyone has any idea to it? I just want to call a async method in page1, and update result to UI in page2. Thank you
Here is an idea: don't make it static. Don't try to create problems for yourself by breaking simple OOP rules like encapsulation, etc and by finding some crazy workarounds around the framework you work with.
When you are in such a situation you should stop, look back and think because it is an indication that you do something completely wrong. Don't try to push it even further by finding hacks and workarounds. Rather you should refactor and reuse the correct paradigm.
For example, if you want to display the result on Page2, then there IS a Page2 ALREADY. So there IS an instance of it. Why do you want to use static handler then?
Probably because you don't have a reference to this page. That's fine, normally you shouldn't.
But when you finish your computation you can publish an event saying "hey, here is the task done". At that point you shouldn't care who is interested in this result, that's not the worker's concern.
Which means that the logic of the computation itself should probably be moved out from Page1. Really, pages concern is dome presentation logic, nothing more.
Page1 should make a request that some computation needs to be done. And here will be an external component (perhaps something in your ViewModel) to actually make it happen.
So when the result is ready to be consumed, you can simply push it into a ViewModel (update some observable properties or collections, etc), so if there is any UI (or many of them, or other components) interested in this data it will be automatically notified and the data will be displayed.
But please don't try to hack around, it will lead you to bigger pain in the future.

Determining what controls needs to be recreated on page load when using multiple Update Panels

I have a page with multiple update panels, each containing dynamically created User Controls that contain a button control.
When The button in a control is clicked the control no longer exists in the page load event and so the click event of the button within the control cannot be raised.
To get round this I am currently recreating ALL the controls on the page in each page load event, but this is obviously causing a lot of unneccesary page updating. In any given partial postback, the only control(s) that need to be recreated are the ones in the update panel containing the control that has been clicked.
How then can I best identify which control has been clicked in page_load and then only recreate the controls in the relevant update panel to be able top then access the click event of that control?
I know I can do the following
if (ScriptManager1.IsInAsyncPostBack)
{
string clickedControlId = ScriptManager1.AsyncPostBackSourceElementID
}
But this isnt hugely useful as knowing the ID of the control doesnt neccesarily help me identify which Update Panel it belonged to. Is there a way of adding a command argument to the control when it is created at run time and reading that command argument in the page load event during the partial postback?
If not, any other suggestions?
Many thanks
Stewart
1) Stop using update panels they add an unnecessary level of complexity that creates more problems than is worth, especially when you have more than one in a page.
2) Stay away from mixing Ajax functionality with server-side logic. You will end up writing a lot of code to compensate one or the other.
What I suggest:
Don’t use update panels!
Keep the code that generates the initial page load. Instead of posting to the server with a .Net button, use a regular button and use the onClick=”foobar_ajax(id, ….Update UI)” to make an ajax call to update the data on the server. Include the ID of the item(the control) you are clicking on. When your ajax call is done you may not need to do anything or you could update the UI with some new data from the server (I recommend refreshing after saving).
Read: Calling the page method with jQuery instead.
http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/

Textbox and focus problems with Timer controls(asp.net)

I am needing to create something like a lock timer(a little thing that just updates a lock time in a database). I thought the Timer control would suite my needs, but whenever the Timer control causes a partial post back, recently typed text in a textbox can disappear(inbetween the post back begin and post back end) and it loses focus.
Because this is only a lock timer, I do not need to refresh any part of the screen, I basically just need to tell the server "hey, don't free my lock, I'm still on this page". So is a Timer control even necessary? Is there an easier way to do this is pure javascript? The only thing I need to know is an ID, which could be kept as a hidden field(and therefore accessible from javascript by DOM)
anyone have any input on how to tune the timer control or a quick javascript way to do it?
edit:
also, I have the updatepanel that contains the timer control outside of the update panel containing the textbox control
If I understand it correctly you need a method which will update the datetime in the database at periodic intervals.
For that you can simply use Ajax. The window.setInterval is a JavaScript function which will fire a piece of code at regular intervals.
window.setInterval(foo,5000);
The above code fires the foo method every 5 seconds.
The only thing you need to lookup is how to call the database. Since, you are already using MS Ajax I suggest you check out ScriptManager control which contains a section for services. Check out the following post which consists of a simple example of how to call WebService methods using MS Ajax:
http://azamsharp.com/Posts/83_Using_FireBug_Profiler_to_Dig_Deep_into_MS_AJAX_and_JQuery_API.aspx

Categories

Resources