Event order changes with a Postback in the ObjectContainerDataSource

Topics: Web Client Software Factory
Dec 13, 2006 at 12:39 AM
I have a question about the best practice here:

The situation is we're using the ObjectContainerDataSource control to feed a DataGrid that shows a bunch of read-only data. We're using the nice new paging capability, sorting, etc. to minimize the data returned from the DB. In general, it works as expected with the PageLoad event happening and then the OnSelect event happening later on.

The problem occurs if we cause a Postback to the page. We have EnableViewState turned off and by doing that, it causes the OnSelect method to fire earlier in the page life cycle - well before PageLoad. This has the problem of the values that were being setup in PageLoad are now not available to the OnSelect command.

If we turn on the ViewState, it never even calls the OnSelect again.

Is this intended behavior? My hope would be that the order of the events on the Postback would be the same as the non-Postback. Otherwise, what would you recommend we do with setting up values in our Presenter - move them out of the PageLoad and into somewhere else that's guaranteed to fire before the OnSelect?

Dec 13, 2006 at 1:17 AM
After some more research, I came upon someone else asking the same question in another situation:
http://forums.asp.net/thread/1272062.aspx

In general, it appears that the ProcessPostData (which happens just before the PageLoad) is trying to recreate the DataSource exactly the way it left it on the last page for you to use. Then, you can do your thing on the page, and let it rebind again to the DB at the very end of the page lifecycle again - just like you would expect.

So - it's this extra data binding that occurs in the ProcessPostData that I'm wondering about. In general, I can see some merit to it if you're trying to have events, data, etc. from the previous page. I can't think of when I would ever really use it, but hey. I also realize this is probably not a P&P issue but a .NET lifecycle issue.

Thus - Since the ObjectDataContainer is a P&P homegrown control - do you think there's any way to have a property that says "Do not reload yourself in the ProcessPostData event"? Or something equivalent and we work around this situation?

Or is there something even easier that I'm just blatantly missing from staring at this for too long?

:)
Adam
Dec 13, 2006 at 2:59 PM
Hi Adam, thanks for the feedback.

If you are using the new server-side paging/sorting functionality, you should not use the Load event of the Page to set the DataSource property of the control, because typically at that point in the page life cycle you don't know the index of the page you have to show. Note that when you request a new page, first the Page.Load event is fired and then the GridView.PageIndexChanged event is fired (assuming you are using a GridView).

Thus, to use server-side functionality you have to set the DataSource property of the control when handling the OnSelecting event. This event is fired when a data-bound control like the GridView asks to the ObjectContainerDataSource control for the items to display. Please refer to the CustomersAdvancedView implementation in the ObjectContainerDataSource Quickstart to see a working example of the control using server-side functionality.

Let me know if I didn't answer your question.

Mariano Szklanny
http://staff.southworks.net/mariano
Dec 13, 2006 at 4:59 PM
Thanks for the response. We are using the OnSelecting event, but on on a Postback it gets called from the first ProcessPostData event (before the Page_Load).

In the standards for WCSF, it's been suggested to put the "main" processing into the PageLoad event. Things such as analyzing other fields on the screen, etc. In general - loading up the Presenter.

If you use the OnSelecting event for ANY datasource, then the OnSelecting event has to be completely self contained within the presenter (think Static) and it will get fired before PageLoad on a postback. In our case, we put much of the processing for the Presenter (which the OnSelecting event relied upon) into PageLoad. On a Postback, it didn't work because of the event ordering.

Our current "hack" is to move much of the setting up of the Presenter into OnInitComplete (which happens before ProcessPostData). This still has the problem that we don't have access to many of the controls on the page, but it made it work for now.

My main reason in bringing this up is that I like the way the WCSF is establishing standards for ASP.NET development and I also like the fact that it's REAL software that can be used in a real world - not just demo ware. I bring this up because I think using OnSelecting means that you should not use PageLoad to do your Presenter initialization - or establish the standard that the OnSelecting events call into Static methods in the Presenter.

Now, my real hope is that I'm missing something and it's actually much easier?

Adam
Dec 14, 2006 at 5:20 PM
---
In our case, we put much of the processing for the Presenter (which the OnSelecting event relied upon) into PageLoad. On a Postback, it didn't work because of the event ordering.
---

Would you mind giving more details about this? What kind of initialization are you doing in PageLoad? Does it require access to controls in the view?

Mariano
http://staff.southworks.net/mariano
Dec 14, 2006 at 8:27 PM
I've spent about 20 hours on this now and have it boiled down to a "rule" that I think need to be followed when using these controls/concepts.

Scenario:

A user logs into a website and their UserID is stored in a Session. They go to a page that shows them paged results in a GridView. The data that the GridView is showing contains 1,000,000 rows so the Custom paging is used. In addition, there's a dropdown above the grid that allows the user to filter the grid based upon some value in the DropDown. The key is that the values in this list are filtered by the UserID also. Very simple scenario.

The first time through the page, everything works. The problem occurs when the user changes the value in the dropdown and hits the "Search again" button next to it.

The Rule: You HAVE to have ViewState enabled for the databound control (GridViews, DropDownLists, etc.) if it's using the CustomDataSource. Otherwise, the OnSelecting event will be fired at the first reference to the control via code. At a minimum, this will be the ProcessPostData event before OnLoad - but probably even earlier. We found it virtually impossible to get the values into the Presenter early enough to allow OnSelecting to process correctly.

This rule is a disappointment because imagine the DropDown list contained 200 entries. I have the entries cached in the web Application, and thus there is no need to send them back and forth via ViewState. I would LOVE to turn off ViewState and just reload the list inside of the OnSelecting event. Doesn't work because OnSelecting will be called before PageLoad which sets up the Presenter - which sets the UserID for the filtering.

The quick Hack:

Put the Presenter code into the OnInitComplete AND PageLoad. The first pass loads the Presenter values necessary for the DataBound controls OnSelecting to function correctly and the second pass loads the values from the DataBound controls themselves after being loaded.

This got kind of complicated and it's a real pain to straighten out in your head, but I think it's a real problem. Again - our answer is to either not use the CustomDataSource if we want ViewState turned off, or make sure the ViewState is on.

Adam