I have an ASP webpage that has 52 custom control all maintaining ViewState by loading in the PreInit routine
It is a report generator page that depending on which report, up to 5 of the custom controls are visible but not all of them.
For instance,
The Client report does not need the Employee questions.
And the Employee report does not need the Client questions.
But both need the Date Range questions.
(and all this works perfectly)
BUT...
I would like to instead LOAD ONLY the controls that are appropriate for the report that the user is running. (Which sound to me) like I need to store information on WHICH controls to load in the ViewState.
Problem is... viewstate is not available in the PreInit routine, so I cannot use it to determine which controls to load.
My options are then to store the information on WHICH controls to load in:
SessionState.
Database
URL argument.
Something else I haven't thought of.
Each of which carries its own problems for doing what I need.
What (in your opinion) is the best practice for this.
My code (snip)
Private Sub WebForm2_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
ReportOptions.Controls.Add(UserControl1)
ReportOptions.Controls.Add(UserControl2)
ReportOptions.Controls.Add(UserControl3)
Etc...
End Sub
My HTML (snip)
<div id="ReportOptions" class="ReportOptions" runat="server"/>
Viewstate is not an option because you must reconstruct your page exactly as it was (controls and all) in order to read the view state correctly on a post back.
Session sux. (single threaded in asp.net provider)
Database is way to heavy and an overkill.
URL method is stateless and probably your best bet.
Related
Is it a "Best Practice" to always use .IsPostBack in the Page_Load sub routine of a web form like in this example coding?
I hope it's ok to ask this question. If not, I will immediately remove the question.
Basically I want to code the way most of you are coding.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
' More coding will go here.
'--------------------------
End If
Please give pros and cons for it's usage.
It's not so much a case of "Best Practice" but more a case of whether you need to use it at all.
It's true, you would normally put IsPostBack in the Page_Load, though you could also put it in the Page_Init - basically in any of the page events that fire before rendering out the HTML.
You're essentially using the command to, in this case, prevent the code in the body from firing when the page posts back to itself; such as a form submission or AutoPostBack on a server control, for example the DropDownList.
There aren't any, at least that I can think of, pro's and con's. Its a case of need or don't.
An example of when you would ideally need it would be only wanting to get data from the database once and bind it to a DropDownList. This data would be available in the viewstate when you postback. so you wouldn't need to visit the database again on postback.
An example of when you wouldn't put code in it is if you were generating server controls (button for example) that have an event handler, such as click, added at the same time. this would need to be re-generated on postback for the event handler to be available.
The benefit is that you can do your expensive operations only once. Binding to gridView...etc.
Mostly stuff you do not want to perform during a refresh.
It always depends on what you want to optimize. If your initialization code takes a long time, it is better to do it only the first time and let your controls be initialize through ViewState. Then you use If Not IsPostBack.
But if you target for mobile devices where bandwidth is more important, you might turn of the ViewState and initialize your data again on postbacks (you could read it from Cache or from SessionState). Always watch your ViewState, I have seen pages with 20 kByte ViewState or more.
Pros:
less overhead for initialization (e.g. access to database)
less memory on server (session or cache)
Contra:
more bandwith for ViewState
I have a Report.aspx page that loads different UserControls to view specific object data alternatively. The UserControls inherit the same base type class where override the specific operations methods. I use a specific Service class for each UserControl to get data which implements a specific interface with operations signatures.
I now use a factory pattern to return the actual UserControl type to the Report.aspx and load it into a PanelControl, then call the control method to fetch some data based on some arguments.
This UserControl should be loaded in every postback due to the dynamic nature of it, any other solution is accepted. On every postback though I don't need to load data from the BL which calls the DL. I try to find a solution to show to the BL that I don't need you to call for the data again because I'm just posting back for other issues (e.g. download a report file, print etc.). And I would like this to happen on the BL level, not the ASPX front end. So far I think that I should let BL somehow know this (PostBack or !PostBack). I guess I could just create a parameter true, false and pass the PostBack property.
Any ideas, architecture and best practices are so welcome.
why not wrap the logic to call the BL inside the if(!Page.IsPostback){....} ?
Can you elaborate your statement "On every postback though I don't need to load data from the BL which calls the DL."?? During each postback, user control needs data to show (even if it is same data as last postback) because usercontrol goes through same lifecycle as ASPNET webpage. How can you prevent that?
I have decided that a very nice solution is System.Runtime.Caching in .NET 4.0.
Works very nice for every layer you need to use it.
http://msdn.microsoft.com/en-us/library/dd985642
Is it possible to save ViewState information, e.g. to session, so that when you navigate away from the page it is persisted somehow? Then when you return to that page you can reload the view state and the choices you've made are preserved.
Background
I have two pages, a report page, where you can pick data, do some filtering and sorting etc. and a chart-page, where the data you picked from the report page can be presented in different ways, with different choices for presentation.
If the user has tested different presentations, simply using the back-button could mean quite a few clicks before the user's back at the report page. I'd like a direct link to the report page.
Using QueryString to save control states is not an option.
I can't customize the ViewState storage for the whole application.
Yes, it's possible to store the Viewstate in something like a database. You just need to implement one of the viewstate providers. See here for an example using the SqlViewStateProvider.
Edit: Just re-read your post, and saw that you said you couldn't customize how the viewstate is stored for the whole application. If that's the case, you might want to look into storing it in a session. Scott Hanselman discusses that here.
Your link could automatically navigate back the required number of pages using JavaScript. Look at window.history, if you can count the number of pages forward you can navigate back that many.
The ViewState is already designed to persist the state of the user controls. If your user has made a selection and that selection is processed server side with a full page postback the new state of the controls will be saved in the ViewState (hidden input __VIEWSTATE).
If your report is using AJAX and partial page postbacks then you won't get the ViewState on the page anyway.
Just to clarify, the SQLViewstateProvider is NOT an application wide implementation. You have to create a class which inherits from the System.Web.UI.Page object and overrides the Save And Load viewstate methods of the Parent Page class. For each page that you want the viewstate to be saved on server side you then have to inherit from your newly created Page Template (Which in turn inherits and overrides the System.WEb.UI.Page class).
So it is applied on a per-page basis, not on an application-wide basis.
HEADS UP: Some controls might contain some client-side javascript code which may reference the viewstate on client-side (duh). If the viewstate is now stored on server-side you will get a null-reference exception (for instance, clicking a commandfield in a gridview). I'm working on a workaround for this problem, but unfortunately I do not have any concrete solution as of yet.
This is a bad idea, just use querystrings. I would be interested to know why they are not an option.
The Problem
When using asp.net server controls id attributes such as the following are automatically generated.
<img id="ctl00_body_ULRepeater_ctl01_LIRepeater_ctl00_PartImg" src="img.png" />
While I'm not averse to id attributes in general, I try to stay away from using these unnecessarily verbose types of names and use concise, descriptive names.
The Question
Can I stop asp.net from generating these id attributes? They look terrible, and if I generate a lot of items with a repeater or something they actually add a good bit of page weight. How do I get rid of them?
Notes
I am using asp.net 3.0 in Visual Studio 2008.
[update]
Ok, so I can subclass (ClientID is declared overridable), but this is no fun really. I can use Literal Controls everywhere. Or I can grit my teeth and bear the painfully slow rendering of my pages with nearly nothing on them.
I believe that one of the features coming in asp.net 4.0 will be the ability to better control the IDs that are generated. For now, you are going to get the name mangling for any server generated control. This is what allows asp.net to guarantee the uniqueness of your control's ID.
You can always use straight HTML markup (do not runat=server) to avoid this issue. You would be sacrificing the ease of use for a lighter weight page though.
You can hide these id attributes completely by setting each control's Id property to null at runtime, e.g.
Private Sub repeNewsletters_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles repeNewsletters.ItemDataBound
If e.Item.DataItem Is Nothing Then
Return
End If
Dim hlDetails = DirectCast(e.Item.FindControl("hlDetails"), System.Web.UI.WebControls.HyperLink)
hlDetails.ID = Nothing
end sub
As of now ControlID's are ReadOnly properties. In the upcoming release of ASP.NET Web Forms (with .NET 4.0) this will be a settable property using a number of different methods (such as static, inherit, etc.)
What's the best way to implement user controls that require AJAX callbacks?
I want to accomplish a few things:
Have events done in the browser (eg, drag and drop) trigger an AJAX notification that can raise a control event, which causes code on the page using the control to do whatever it needs to do (eg, change a value in a database).
Have partial updates (NOT using an updatepanel) that can do things like populate an auto-complete dropdown underneath a textbox.
Implement a single user control that is generic enough to be reused on several pages
Avoid having to implement logic on the page itself that passes events back to the control, because that is repetitive and hard to maintain
I'm using jQuery for most of the client side stuff, but for the actual AJAX calls I don't really care if it's jQuery or the ASP AJAX libraries.
Effectively what would be perfect is PageMethods on the user control, that would be easily callable from client-side script. Unfortunately, as far as I'm aware, pagemethods do not work on user controls.
I'll use an autocomplete control as an example:
I should be able to put the autocomplete control on the page, and then in the page code, have eg:
Public Sub HandleLookup(ByVal input As String, ByRef list As List(Of String) Handles MyControl.LookupEntries
list = New List(Of String)
' Query database for list of items..
For Each item as String in FullItemList
If item.StartsWith(input) then list.Add(item)
Next
Return list
End Sub
And do nothing else .. the rest of the code should be in the usercontrol.
Note, the controls I'm trying to make are much more specific than eg, autocomplete. They do not exist in any 3rd party libraries and I really need to be able to make them myself.
Look into implementing ICallbackEventHandler in your Page -- it's a simple way to make a call back to a page function from JavaScript.
Here's a good tutorial:
http://www.ajaxprojects.com/ajax/tutorialdetails.php?itemid=119
You might want to check out; Ra-Ajax UserControl Sample and combine that knowledge with Ra-Ajax Drag and Drop
Click the "Show code" C# icon to the left to see the usage of the code...