Why can't i access page viewstate in usercontrol? - asp.net

I stored a object in viewstate on Page. Now when i access the same viewsate object on usercontrol,it shows as null. I even tried creating the same viewstate with same name in usercontrol and page.Both holds different value.
I understand that viewstate is a protected property. How does this thing implement in above scenerio or is there any other reason for this behaviour.
Edit:
Usercontrol is there in the page markup. I am not loading it dynamically.
I have a page EditFacilityworkType.aspx. On page I have a usercontrol FacilityWorkTypeDetails.aspx(FacilityWorkTypeDetails1). Inside this usercontrol i have a user control Workflow.aspx(Workflow1)
Page_Load() of Page
I am retrieving workflowdetails on page_load() of page.
FacilityWorktype facilityWorkType = facilityDetails.GetFacilityWorktypeDetail(SessionHelper.FacilityWorkTypeID);
ViewState["WorkFlow"] = facilityWorkType.FacilityWorkTypeWorkFlow
Inside usercontrol FacilityWorkTypeDetails.aspx. I have a property
public FacilityWorktype FacilityWorkTypeDetails
{
get
{
#region Fill FacilityWorktype
return GetEntityFromControl();
#endregion
}
set
{
PopulateControls(value);
}
}
Now i set this property in page load of page
FacilityWorkTypeDetails1.FacilityWorkTypeDetails = facilityWorkType;
Inside Workflow.aspx, I have a property
/// <summary>
/// Property to fill entity object from controls on this page
/// </summary>
public WorkFlow WorkFlowDetails
{
get
{
return GetEntityFromControls();
}
set
{
BindTranscriptionMethodDDL(ddlTranscMethod);
PopulateControls(value);
}
}
Now PopulateControls() of FacilityWorkTypeDetails1, i am setting property of workflow1
private void PopulateControls(FacilityWorktype value)
{
Workflow1.WorkFlowDetails = value.FacilityWorkTypeWorkFlow;
}
Now when i am retrieving values from
private WorkFlow GetEntityFromControls()
{
WorkFlow workFlow = (ViewState["WorkFlow"] as WorkFlow) ?? new WorkFlow();
//workFlow is null
}
So now inside this function workFlow is null. I want to ask,why is it null when i have set viewstate in page.

Scherand is very correct here. I'd like to add to what he has brought to the table.
Every control that derives from System.Web.UI.Control has the ViewState property. Under-the-hood the property is a StateBag collection. Every instance of a Control has its own StateBag for ViewState, so as Scherand mentioned, ViewState is unique to the control. When the page gets rendered, the entire Control tree of the Page is iterated, all ViewState collections are merged into a tree-like structure and that final structure is serialized to a string and rendered to the page.
Because the ViewState property is marked as protected, you can't get to the Page's ViewState from your User Control without the use of reflection.
But, in all honesty, you should abandon the use of ViewState as a data storage medium. Here are some reasons why:
ViewState gets rendered and output to the client browser. Maintaining data objects in the collection bloats your Page's output.
Unless you have encryption enabled on your ViewState, the encoded string that is rendered to the client browser can be decoded manually and simply anyone can access the content of your data objects. This is a rather significant security vulnerability.
It really sounds like all you want to do is share data between your Page and User Controls. The best way to share data between controls is to make use of the "Items" collection (which is a property of the HttpContext class). The collection is a Hashtable and can be accessed from your Page and User Controls like so:
Context.Items["Workflow"] = workflowInstance;
The best part of using this technique is that it doesn't incur any additional overhead or bloat the Page output. The Items collection exists in the context of a single HTTP request. This means that when your request is done and your Page's output has been rendered to the client browser, the Items collection is cleared from server memory. It's the ideal medium for temporary data storage within ASP.NET.
Now, if you want your data objects to remain accessible for more than just the current request, you'd be better off storing the objects in Session.

I still do not grok everything here (see my comments above). But I am pretty sure you are misunderstanding ViewState.
ViewState is per control, not per request or session or whatever.
In your example, consider some other control (e.g. a standard ASP.NET control) that for some reason decided to put something with a "name" of WorkFlow into viewstate. If what you are trying to do would work, this object would overwrite yours (or the other way around, yours would be overwritten by the other one).
Or am I missing something?
Maybe reading TRULY Understanding ViewState could help you understand what viewstate is/how it works (yes, I really like this article, this is why I keep posting that link).

On postback did you create the control? If the code behind hasn't created the ctrl then it won't know about it.
only applicable if this is a generated control. You may need to post code and more info to get a propper answer.
Viewstate is a monster which is why a lot of us are going to MVC.

the page viewstate is a different statebag from the viewstate that the usercontrol can access. each control has their own private viewstate. So you cannot directly access the page viewstate from a usercontrol code-behind.
you could expose viewstate values with properties or methods and then call those properties/methods

Related

short string representing Viewstate Visible even if view state on each and every control is disabled

I disabled the viewstate on page and each control within it. But I still see short string representing the viewstate in the page source.
I created a page with two controls, one a checkbox and other a texbox. I completely disabled the viewstate for both the controls and the page. But I still see a div rendered which contains the viewstate in the hidden variable:
<div class="aspNetHidden"> <input id="__VIEWSTATE" type="hidden"
value="/wEPDwUKMTcwNTQzMjY4MWQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgEFG‌​
2N0bDAwJE1haW5Db250ZW50JGNoYm94VGVzdPRq7jJUwzyCcKYfAFB/seRcAvziSp3bKL23H9U7O9sU"
name="__VIEWSTATE"> </div>
Can anyone help in understanding this behaviour of asp.net
1) You must have a server-side form tag () in your ASPX page if you want to use ViewState. A form field is required so the hidden field that contains the ViewState information can post back to the server. And, it must be a server-side form so the ASP.NET page framework can add the hidden field when the page is executed on the server.
2) The page itself saves 20 or so bytes of information into ViewState, which it uses to distribute PostBack data and ViewState values to the correct controls upon postback. So, even if ViewState is disabled for the page or application, you may see a few remaining bytes in ViewState.
3) In cases where the page does not post back, you can eliminate ViewState from a page by omitting the server side tag.
http://msdn.microsoft.com/en-us/library/ms972427.aspx
It's the control state.
If you really want to get rid of viewstate and controlstate you can use this code in the code-behind for the page, or in any class that the code-behind derives from
class MyPage : Page {
private class DummyPageStatePersister : PageStatePersister {
public DummyPageStatePersister(Page p) : base(p) {}
public override void Load() {}
public override void Save() {}
}
private DummyPageStatePersister _PageStatePersister;
protected override PageStatePersister PageStatePersister {
get {
if (_PageStatePersister == null)
_PageStatePersister = new DummyPageStatePersister(this);
return _PageStatePersister;
}
}
// other stuff comes here
}
Be very careful when doing this, though, since you're violating the contract with the controls. MSDN explicitly states that control state is always available. In practice, however, it has worked for me.
Edit:
Since I was downvoted, I like to point out again: Don't do this unless you know exactly what you are doing. In my case, almost the entire application was written in client-side javascript, and on those few occations where postbacks occurred, I always used the Request.Form collection to retrieve the values. Do not use server-side controls for anything but simple rendering if you do this.
No, you can not get rid of View State completely. You will always have a relatively short string representing the page itself even if you turn off the view state on each and every control.
Check State Management (View State).

Overriding DataBind on User Control, caveats?

I've a custom property on a user control which has multiple state/modes. If this property is set in the parent page: I would like for my control to update automatically. Using the property in the page load does not work because it is not initiated.
I can imagine 3 methods to do this:
On the property, I could add a code block that would call this.DataBind().
I could add the code by overriding the virtual method DataBind.
I could create a public proprietary Update method.
I would like any input into what is the best practice in general. More to the point, I've chosen to override the virtual method DataBind. My pseudo code is as such:
public override void DataBind()
{
if (SpecialMode)
{
.. load from database
}
base.DataBind()
}
I'm interested in the ordering of the base.DataBind(). I've seen it typically placed first but after I load the data from the database: I will need to databind to get the data to display.
Any input into these considerations will be greatly appreciated.
To be clear:
This control is a Poll widget. It will typically search and load the poll to display from the Page_Load event. But, it also has a reports mode which allows the page in which the control is embedded to change the Id of the poll to display. This property will not be initiated in Page_Load. Okay, part of this mess is that I've a property for an object, and I've also a duplicated property for the ViewState but only the Id.
You could have your user control handle the automatic databinding in its PreRender event. When the Id property is changed (or whatever property it is that triggers the automatic databinding) you could set a flag within the control that is later checked in PreRender to indicate that data needs to be loaded.
Alternatively, instead of setting a flag you could possibly clear any data that you've already loaded from ViewState and implement logic in PreRender to say "If there is no data, then load it".
This avoids potentially loading data multiple times within a single request due situations where there happens to be code that sets the Id property multiple times.
Your control should not depend, in any way, on the page in which it is embedded. Instead, have an "AutoUpdate" property on the control, and have the page set it. The page should also set properties telling the control how to update when the AutoUpdate property is set.

asp.net code behind variable

I am generating some head html in page load and because of that I query database once. in the page I query database again and put data into html with inline code.
my question is is there better way to do this? I dont want to query database everytime and reach out those filled variables from inline code. something like page.addVariable in page_load and reach those at inline like page.variables["variablename"]
thanks in advance
If I understand what you are asking, you can make an accessor and set it to Protected. That will allow you to access it from the page.
If you want to prevent calling the database on callbacks, you could always add the information to the view state on the page.
Information on the view state, hidden fields, and cookies:
http://www.csharphelp.com/archives/archive207.html
I'm not sure if this is what you're after, but you can use a HiddenField to store any data you want on the page.
Also, if you don't need it to be on the page, you can use Session or ViewState.
Here's an example of using ViewState as a property (NB. you can interchange ViewState with Session, look at the links I gave you for an explanation between the two):
public string YourProperty
{
get
{
object content = ViewState["YourProperty"];
if (content == null)
{
return string.Empty;
}
return content.ToString();
}
set
{
ViewState["YourProperty"] = value;
}
}
Note, that anything you put into ViewState or SessionState must be marked as Serializable.
If it's quite a simple class, just mark the class with the [Serializable] tag.
Is the data you retrieve from the database page specific, user specific or global to the entire application?
If the data is user specific you can use Session State.
If the data is global to the entire application you could use Application State.
Whichever you use, you can implement the data retrieval in the Session_Start (will be called only once for each user) or Application_Start (will be called only once when the web app starts) events in a Global.asax file.

ASP.NET: Exposing a Web User Control's controls

I've created some Web User Controls (.ascx files) and dropped them into Pages. The user controls have some TextBoxes in them that I'd like the Page to be able to access directly.
What's the easiest (read: least time) way to expose these TextBoxes in the user controls to the Pages containing the user controls?
The two options I know are calling myUserControl.FindControl(id) from the Pages (does this even work from the Page?), and writing properties in the user controls to expose the TextBox values.
Neither seem ideal. FindControl() requires the Page know the IDs of the TextBoxes in the user controls, thereby breaking encapsulation and adding hard-coded strings, and writing a bunch of properties in the user controls will be very time consuming given the number of TextBoxes in these user controls.
There's no way to declare these TextBoxes in my user controls be public instead of protected?
(Setting aside the obvious comments about the fact that what you're describing is essentially the opposite of best practice...)
If you are using a Web Application type project, you should have a designer.cs file for each UserControl. That contains the declaration of each child control, so you can change the access modifier to public.
If you are using a Web Site type project, you should probably convert to Web Application. According to Microsoft (and backed up by experience), the Web Site type is not intended for use when you plan to write extensive code which spans beyond a single code-behind.
If I have to do this I will write a public property that exposes the controls. However there is usually a way to rewrite the information such that you don't need to expose the internal controls. If all you need is the value, create a property that returns the value. If you need client ids, perhaps creating a client object that exposes values or events will solve the issue. Remember, once you make it public, you are exposes a contract and changing that contract will almost always be painful.
You can expose it as a property from the code behind. You'll really only be able to access it's properties from code, not from the ASP.Net designer though. This is an example in vb that exposes a DropDownList on a user control (and, it may not be a best practice but it certainly beats writing code to expose every property on the child controls):
''' <summary>
''' This is the exposed DropDownList for this control.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property DrowDownList() As DropDownList
Get
Return ddControlList
End Get
End Property
Why not give your user control a collection of TextBoxes, expose the collection as a property, and in your Init() method, just add all your textboxes to the collection?
That way, you have a collection that you can search by ID if you ever need to, without relying on any page logic, and you only have to expose one property. If you make your own collection class for it, you could even program in a couple of handy methods for accessing the textboxes the way you need to.
Derive all of your Web User Controls from a common base class and expose this functionality as a public method (or methods). Your base class can derive from UserControl (the way an .ascx normally would) and your controls in turn derive from it.
Then, even if using reflection seems like a bit of work, you're only doing it once. If the textboxes are dynamic and you want to avoid hardcoding things, this would be the way to go.
So, if you need to just get the value of the text box by id from a parent, you can add something like the following to your base class:
public string GetTextboxValue(string id)
{
string textValue = string.Empty;
Control ctl = FindControl(id);
if (ctl.GetType() == typeof(TextBox))
textValue = ((TextBox)ctl).Text;
return textValue;
}
I'd say to go this route vs. the previous suggestion of making the TextBox public since you really only want to read the text value from the parent and not expose the entire object as read/write.

ASP.net ViewState - Even when disabled, some viewstate exist. Why?

Even when on the page, the EnableViewState property is disabled, I am still seeing some viewstate existing on the page:
"<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="VkBAB3n5LZYtY+nTzk1vEu1P/6QLf4qzFIKzpFRJe3DMf8UseUA/1RsO409HJX4QhkROSP0umoJvatjK/q+jXA==" />"
My question is why?
It's the control state.
If you really want to get rid of viewstate and controlstate you can use this code in the code-behind for the page, or in any class that the code-behind derives from
class MyPage : Page {
private class DummyPageStatePersister : PageStatePersister {
public DummyPageStatePersister(Page p) : base(p) {}
public override void Load() {}
public override void Save() {}
}
private DummyPageStatePersister _PageStatePersister;
protected override PageStatePersister PageStatePersister {
get {
if (_PageStatePersister == null)
_PageStatePersister = new DummyPageStatePersister(this);
return _PageStatePersister;
}
}
// other stuff comes here
}
Be very careful when doing this, though, since you're violating the contract with the controls. MSDN explicitly states that control state is always available. In practice, however, it has worked for me.
Edit:
Since I was downvoted, I like to point out again: Don't do this unless you know exactly what you are doing. In my case, almost the entire application was written in client-side javascript, and on those few occations where postbacks occurred, I always used the Request.Form collection to retrieve the values. Do not use server-side controls for anything but simple rendering if you do this.
This could be controls that are using ControlState. Any control that has control state will ignore your ViewState settings.
This article is a little old but to my understanding most of the points are still valid:
You must have a server-side form tag () in your ASPX page if you want to use ViewState. A form field is required so the hidden field that contains the ViewState information can post back to the server. And, it must be a server-side form so the ASP.NET page framework can add the hidden field when the page is executed on the server.
The page itself saves 20 or so bytes of information into ViewState, which it uses to distribute PostBack data and ViewState values to the correct controls upon postback. So, even if ViewState is disabled for the page or application, you may see a few remaining bytes in ViewState.
In cases where the page does not post back, you can eliminate ViewState from a page by omitting the server side tag.
http://msdn.microsoft.com/en-us/library/ms972427.aspx
This is an absolutely fantastic article on ViewState if you develop in ASP.NET read it!
ASP.NET ViewState Helper is also a nice tool for seeing what's going on in your ViewState
Controlstate can be the causes. Control state can not be disabled. In ASP.NET 2.0 there is a distinction between data necessary to make a control work (controlstate), and other data (viewstate)
And yes some of the controls don't work without controlstate.
If you want to know which one is causing it or what the viewstate contains check out a viewstate viewer
The Controls which implements IPostBackEventHandler like Textbox, Checkbox, etc. will retain the state even after disabling the viewstate. The reason is during the Load Postback Data stage, these controls will get state information from Posted back form.
But controls like label which do not implement IPostBackEventHandler will not get any state information from posted back data and hence depend entirely on viewstate to maintain the state.

Resources