can't turn off ViewState (asp.net/VS2010), what can be wrong? - asp.net

I'm working on an application which generates a list of customers from a db. I have disabled ViewState in default.aspx, but now when I viewed the source code of the generated HTML page I saw that the ViewState is on.
I've tried to add both ViewStateMode="Disabled" and EnableViewState="False" (separately and even together) without any luck.
What can be wrong?
ViewState code from the source code if it helps:
<div class="aspNetHidden">
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="88luWaDvrTt0+OWLhB and a lots of characters after this...
EDIT: Now when I looked again in the source code I can see the following which I find strange:
There's A LOT of ViewState characters (takes 15-20 seconds to scroll through it)
There's two places with ViewState code, separate from each other

ASP.Net pages have both Control State and View State. Control State is for absolutely critical data that the control can't function without (at least in theory).
View State and Control State are both stored in the same field. A site with View State completely disabled may still have Control State.
Unfortunately, ASP.Net is quite inconsistent as to how it differentiates between the two. For example, a DropDownList will no longer fire change events with View State disabled. I consider that a critical function of a drop down and I would be happy to spend the few bytes of space to store the currently selected value in Control State so that a change could be detected.
If you are wondering about the contents of the hidden field containing state, you can decode it. It can be very useful for detecting View State "leaks".

Looking at the MSDN documentation, even when you disable it, it is still used to detect postbacks:
Even if EnableViewState is false, the page might contain a hidden view
state field that is used by ASP.NET to detect a postback.

You can deserialize the viewstate to see who's putting data in there:
LosFormatter lf = new LosFormatter();
object deserialized = lf.Deserialize("!!! YOUR VIEWSTATE HERE !!!");
Attach a debugger and have a look at the contents of deserialized

Related

If WebForm would be worthless disable ViewState?

I'm a new comer to ASP.NET. Before that, I was a classic ASPer.
As I know:
ViewState use to maintain some complicate-property(sorry for my arbitrary description.Only to differentiate basic property like value).
ViewState go with PostData and back to server in PostBackData.
ViewState record the latest control status. Compare it with PostData to determine if a event should be fire like SelectedIndexChange.
WebForm is Event base and disable ViewState this engine failed. But ViewState could be mighty.
On some well-known Asp.Net sites like
https://stackoverflow.com/
http://www.codeproject.com/
when I look over source code.I can't see something like
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="31zA00LgYW9+3QuC4YmxF4w3eBAWhuZRL89OB+6X4AwCFpYIR2914D5a4PWubGveAods0+i/2T21mmpYlHx/sv+5gsGfyYPd0bhj76B0yy4=" />
Does those websites never use a runat="Server" and disable ViewState?
If so, I don't Know the reason to use WebForm when throw away ViewState. Why not MVC?

asp.net view state

Is it possible to get the value of the view state that ASP.NET writes in:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="..." />
, before the processing is done for the page, in C#, in one of the page events, such as
OnSaveStateComplete
If so, how?
Thanks!
Simple answer - no.
You could start playing with internal methods like System.Web.UI.Control.SaveViewStateRecursive using Reflection but you have a very good chance that whatever you will build will stop working on the next .NET Framework update.
If you want to provide custom storage mechanism for ViewState you would implement PageStatePersister.

Control.UniqueID different after cross-page postback

I have a simple ASP.NET page with a MasterPage. Within the MasterPage, I have two login fields:
<input type="text" runat="server" id="txtUserName"/>
<input type="text" runat="server" id="txtPassword"/>
When the controls are rendered to the page, ASP.NET renders the following:
<input type="text" runat="server" id="ctl00_txtUserName" name="ctl00$txtUserName"/>
<input type="text" runat="server" id="ctl00_txtPassword" name="ctl00$txtPassword"/>
If I understand correctly, the name attribute corresponds to the UniqueID property of a control. However, when I'm debugging Page_Load and attempt to view the UniqueID of these fields, they have different values (ctl0$txtUserName and ctl0$txtPassword respectively)!
Note that this does not seem to be an issue on all pages using this MasterPage. Most of them work correctly and use ctl0$txtUserName and ctl0$txtPassword in both rendering and Page_Load.
Any idea what might cause ASP.NET to render a different UniqueID for a control than it uses in Page_Load?
I'm still not sure what was causing the generated UniqueIDs in the MasterPage to be different in Page_Load than when rendered to the page. However, I was able to get around the issue by storing the UniqueIDs of these fields in hidden fields. I was then able to access the values directly in the Request.Form collection.
In other words, I did this:
In the MasterPage -
<input type="text" runat="server" id="txtUserName"/>
<input type="text" runat="server" id="txtPassword"/>
<input type="hidden" id="txtUserNameUID" value="<%=txtUserName.UniqueID%>"/>
<input type="hidden" id="txtPasswordUID" value="<%=txtPassword.UniqueID%>"/>
During Page_Load of the child page -
string username = Request.Form[Request.Form["txtUserNameUID"]];
string password = Request.Form[Request.Form["txtPasswordUID"]];
Hope this helps anyone else struggling with UniqueID weirdness in ASP.NET!
Weird quirk I just became aware of: any wrapping controls that are runat server must also have IDs. For instance, if you have a panel around the control, i.e. whatever "ctl00" is, it must be assigned an ID. If it is not set, it will be allocated one and this can change.

Why are hidden fields considered client side state management?

According to MSDN and the MCTS self-paced training, asp.net can use Hidden fields for client-side state management. The book material goes on to say view-state is more secure than hidden fields because the data is encrypted.
I must be missing something here. I setup a Label and made it hidden. I can store data in this hidden label and it won't even be sent to the client browser. This not only works like server side state (note the runat=server), but this seems more secure than view-state because there's no need for encryption as the client can't even see the field.
<asp:Label ID="Label1" Visible="false" runat="server">secret info</asp:Label>
Contrast this with an HTML input field. Here, the client state info makes sense.
<input id="Text2" type="text" style="visibility:hidden;" value="secret 99" />
So what's the deal?
When you create a label in .net and set it's visibility to Hidden, it does not render to the client and its data is stored in viewstate.
Therefore, it is not "more" secure than viewstate as it is using viewstate to maintain the data.
Regarding hidden fields, there are four kinds: First up is the regular HTML one which is simply an input of type hidden. This has no visible rendering although it is in the html. It also has no viewstate properties. It is declared as:
<input id="MyId" type='hidden' value='whatever' />
The second one is a regular input with a css property marking it as hidden: If CSS is disabled or otherwise overriden then the control would be visible to the user. Other than that its pretty close to the same thing as a type='hidden'.
<input id='MyId' type='text' value='whatever' style='visibility:hidden' />
The third one is the .Net hidden field. This does has viewstate storage, but it also causes a regular hidden field to be generated in the html.
<asp:HiddenField id='MyId' runat='server' value='whatever' />
And, the fourth one is a regular .net text box that is marked as not-visible.
<asp:TextBox id='MyId' runat='server' Text='whatever' Visible='False' />
The .net ones will cause data to be placed in viewstate. The HTML ones do not. If you set Visible=False on a .Net control then it is not rendered to the client however it's data is typically stored in viewstate.
There are other ways of throwing data into the page, but they are derivations of the above.
Generally speaking if you have a value that your javascript code needs but you don't need to display it to the client then you use a hidden field (html or .net). If you have a secret value then typically you don't want this to go to the client side if at all possible. And that means even keeping it out of viewstate. As a side note, don't depend on viewstate "security' there are tools out there which will easily decrypt it.
A field which is not displayed is not a hidden field (even though it is "hidden").
Hidden fields are <input type="hidden" name="somename" value="somevalue" /> fields. And those can be manipulated by users.

Viewstate Compression Issues

I'm currently fighting with the .NET Viewstate and it is starting to wear me down. Having found that some of the pages in one of our applications is made up of around 80% viewstate I have looked into reducing this where I can.
I have looked at (and am happy with) disabling viewstate for controls that do not need it (labels, buttons etc) and have made some small gains here.
I'm now looking at viewstate compression and while I can demonstrate a 40-50% decrease in size it does not seem to be playing well with my application.
Scenario:
Page contains a few dropdown lists, a button and a Grdiview (hence the need to deal with the ViewState!). When the page loads the DDLs are populated and default selections are made. Pressing the OK button results in the Gridview being populated as expected.
Now the problem: With Viewstate Compression enabled, if the user changes the selected items in the DDLs before clicking the OK button they will get a 'Required Field Validator' error indicating that a selection has not been made in one of the DDLs - but this is not the case! Disabling the compression code removes the problem and the page operates as expected (i.e. as it has for months!).
Could the problem be down to the viewstate now being stored in a key other than __VIEWSTATE [the code that I have seen use different key names - VSTATE for instance).
My page sources look like this;
Page Source with Compression (note the empty __VIEWSTATE key):
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VSTATE" id="__VSTATE" value="H4sIAAAAAEAO29B2AcSZYlJ
.
.
MKd2afqdaImFR5UiFXVyQPwLPA//8xt+pMsSQ8vlOklcoNgmZfJd8hHvk6/S/7UbxxAJTjzZfp6Qcm039
h3d3dvvPO7/Oa/7i57uemj1H2a/gw5lJQ+ySjFRtPZUL7A/3o2ImFR5UiFXVyLPA+38At70F1EkwAAA=" />
<input type="hidden" name="__VIEWSTATE" id="
__VIEWSTATE" value="" />
</div>
Page Source without Compression:
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTYxOTM1NDg4N
A9kFgJmD2QWAgIDD2QWAgIFD2QWAmYPZBYKAgEPZBYIAgcPZBYCAgMPDxYCHgRUZXh0BRdEYXduQyBbY2hhbm
dlIHBhc3N3b3JkXWRkAgkPFgIeB1Zpc2libGVoFgQCAQ8PFgIfAAUFQWRtaW5kZAIDDw8WAh8ABQUxNDoyNGR
.
.
.
.
.
.
kAgsPDxYEHwAFWVNlbGVjdGVkIFNlcnZpY2UgVXNlcjogPGEgY2xhc3M9J3N1U2VsZWN0b3InIGhyZWY9J2xp
c3RzZXJ2aWNldXNlcnMuYXNweCc+PGI+bm9uZTwvYj48L2E+HwFoZGQCDw8QZGQWAGQCBQ8UKwADZDwrABQEA
BYSHg9QYXJlbnRJdGVtQ2xhc3MFC2lnbW5fUGFyZW50HhdUb3BMZXZlbFBhcmVudEl0ZW1DbGFzcwUTaWdtbl
Ub3BFBhcmVudB4KSlNGaWxlTmFtZWUeFlRvcExldmVsSG92ZXJJdGVtQ2xhc3MFNGlnbW5fVG9wTGV"
/>
</div>
How does .NET know where the VIEWSTATE is stored and does it know that i have moved it?
Do I need to make any other changes to my code apart from implementing SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium?
hey viewstate compression works for me without any problems. basically i have a baseclass for all my aspx pages which use viewstate. even i am using a different viewstate key to save my viewstate. however you have to override 2 methods for this:
1) - to save viewstate
2) - to load viewstate
as long as you are doing this, you should have no problems. see below code which i am using for my baseclass
using System;
using System.IO;
using System.Web.UI;
namespace XC.UI.WebForms
{
public class PageBase : System.Web.UI.Page
{
protected override object LoadPageStateFromPersistenceMedium()
{
string viewState = Request.Form["__VSTATE"];
byte[] bytes = Convert.FromBase64String(viewState);
bytes = XC.Common.ViewStateHelper.Decompress(bytes);
LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(Convert.ToBase64String(bytes));
}
protected override void SavePageStateToPersistenceMedium(object viewState)
{
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
formatter.Serialize(writer, viewState);
string viewStateString = writer.ToString();
byte[] bytes = Convert.FromBase64String(viewStateString);
bytes = XC.Common.ViewStateHelper.Compress(bytes);
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
}
}
}
if you are using ajax in your page please change this line of code. It will solve your problem.
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
replace above statement with ScriptManager.
ScriptManager.RegisterHiddenField(this, "__VSTATE", Convert.ToBase64String(bytes));
There is a constant hidden in .NET that holds the viewstate field name. We did compression by hooking in the methods you describe but keeping the viewstate name same without issues.
This may be overkill, but there is a very cool hardware solution to this problem at www.strangeloop.net. No affiliation, just impressed by the technology.
Back to the page tho - what kinds of controls are generating all this viewstate? Grids? You indicated you went over this already, but do watch out for 'unnecessary runats' with tables, td's, tr's, div's, etc. that have runat="server" set. The entire contents of those controls get persisted in viewstate. We recently chopped 40% off our viewstate payload by recognizing a div was client-side and didn't need runat="server".
Compression didnt work for me as it just got it down by 40%. I had 200-300KB ViewStates and was degrading application performance drastically.
I wrote some viewstate substitution technique which replaced it with a GUID token on the page and saved the actual data on server itself in a database.
Here is the code and technique.
http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/
The following answer is not mine, but OP's (that was included in the question). I'm moving it out of the question and making this a community wiki.
I've got to the bottom of this - well almost, I have it working! For some reason using the ClientScript.RegisterHiddenField method appears to have been the source of the problem. Modifying the code to utilise the base class save method, i.e. base.SavePageStateToPersistenceMedium(compressedBytes) and processing the Pair object returned by base.LoadPageStateFromPersistenceMedium() I now have a working solution. Test show a reduction of aroun 70% on the test page so I'm pretty happy with that.
Now that I have compression working I need to recommend that the next (first proper) Code Review has a focus on removing viewstate where it is not needed.

Resources