Categories
Technology

Invalid State Crashes Client?

It’s the infamous view state again. My my my. I knew there were reasons I really didn’t dig the complexity ASP.NET were trying to cover up. This time though, my sense of amazement reached new heights when the client browser crashed (yip-crashed) because the server picked up some dodgy view state. Read that again. Carefully.
Oh. And you probably might have already guessed which browser does the crashing. No prizes for getting it right, sorry. The correct and predictable, even appropriate response is: “The view state is invalid for this page and might be corrupted” which is what all the other browsers I’ve tested on so far show. On with the experiment…

We’ll start off with a simple ASPX page. Nothing complicated.

<html>
	<script language="C#" runat="server">
  public void Page_Load(Object sender, EventArgs E)
  {
  }

  public void Submit_Click(Object sender, EventArgs E)
  {
  }
	</script>
	<body>
		<form id="Form1" runat="server">
			<asp:Button ID="Submit" OnClick="Submit_Click" Text="Submit" Runat="server"></asp:Button>
		</form>
	</body>
</html>

Click on the button and woohoo- no surprises. But now we add a little extra something. We modify the contents of the page after it’s loaded. Nothing special here either really. Standard AJAX behaviour.

<asp:Button ID="Submit" OnClick="Submit_Click" Text="Submit" Runat="server"></asp:Button>
<div id="dynamic_content"></div>
<script type="text/javascript">
//<![CDATA[
  window.onload = get_dynamic_content;
  function get_dynamic_content() {
    //....
  }
//]]>
</script>

The JavaScript function get_dynamic_content() will make a request and then proceed to populate the div dynamic_content with some more HTML. The obvious solution is to do something along the lines of:

function get_dynamic_content() {
  document.getElementById('dynamic_content').innerHTML = '...some html...';
}

Incidentally, therein lies another rub in that div.innerHTML behaves differently for IE. Take a peek for yourself. And within all those comments, of this article, there lies a hack solution. You can read more about that debate there. Moving along.

So having hacked the little piece of innerHTML magic, you start populating your element with all sorts of dynamic content. Wonderful. Then during a series of development efforts, you get a buggy piece of HTML tagging along for the ride. A second form element- don’t worry, not a server-side form. More about why and why not here if you not too sure about how that fits into the scheme of things. Anyway, so you get an erroneous piece of HTML coming through- a valid bug in the development effort- and your second form contains an extra view state element. By now, you’ve also probably deciphered the design and architecture of this piece of handy work.

And i’ll recount here- this may be a valid bug, but it’s not about the bug. It’s the way the client browser handles a server-side bug.

So let’s assume that part of the payload (simplified) includes the following:

<form>
...
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEWAgL9hvuOBAK8w4S2BGRm0HOf1YSq2O4B5nwrlp8eUNwR" />
...
</form>

You click on Submit. Is this what you would be expecting?

Familiar Browser Crash
Familiar Browser Crash

It’s not even bad HTML. In fact, if the dynamic payload didn’t include the extra form element, just the viewstate ala

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEWAgL9hvuOBAK8w4S2BGRm0HOf1YSq2O4B5nwrlp8eUNwR" />

You get the reasonable and correct behaviour. ASP.NET complains about the view state being fudged. Good. But wrap that extra view state input element in a form tag and IE client blows up. WTF? Incidentally, the form wrapper is arguably more correct.

Here’s the full code for your enjoyment. Modify the content variable and element type of dynamic_content and test across all your browsers.

<html>
	<script language="C#" runat="server">
  public void Page_Load(Object sender, EventArgs E)
  {
  }

  public void Submit_Click(Object sender, EventArgs E)
  {
  }
	</script>
	<body>
		<form id="Form1" runat="server">
			<asp:Button ID="Submit" OnClick="Submit_Click" Text="Submit" Runat="server"></asp:Button>
			<div id="dynamic_content"></div>
      <script type="text/javascript">
      //<![CDATA[
        window.onload = get_dynamic_content;
        function get_dynamic_content() {
          var content = '<form><input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEWAgL9hvuOBAK8w4S2BGRm0HOf1YSq2O4B5nwrlp8eUNwR" /></form>';
          //document.getElementById('dynamic_content').innerHTML = content;
          swap_content_div(document.getElementById('dynamic_content'), content);
        } 
        function swap_content_div(old_div, content) {
          someHtml = content;
          var newDiv = document.createElement(old_div.tagName);
          newDiv.id = old_div.id;
          newDiv.className = old_div.className;
          newDiv.innerHTML = someHtml;
          old_div.parentNode.replaceChild(newDiv, old_div);
        }
      //]]>
      </script>
		</form>
	</body>
</html>
Categories
perspective

Dynamically Nested Controls ASP.Net

The solution seemed simple enough and what’s more, it should have been a straightforward implementation. Should have been. After one or two false starts, we settled into an approach until we hit the ubiquitous viewstate issues. It’s a silly problem to be having really, given that every asp.net server control automatically manages its own state. True, there are constraints and conditions, nonetheless, the theories are not rocket science.

The page dynamically loads a “layout” usercontrol, depending on user context. This layout dynamically nests a “view” usercontrol, again depending on module within the application. This view then dynamically loads one of n “function” usercontrols on a postback. And therein lies the rub. This function itself posts back data from it’s children, one of which is typically a repeater or other custom usercontrols. Further, each repeater item may contain N server controls. After the postback, the page loads and all the viewstate across all the dynamically nested controls and their children load perfectly, viewstate intact. Simple.

The concepts: each server control maintains its own viewstate [good encapsulation]. The viewstate is heirarchically defined and processed at specific points [good definition]. This is a recursive situation, so if it works for one layer, it must work for N layers. The problems: confusing my requirements with another blog’s requirements, vague newsgroups and technical expressions, sometimes ambiguous documentation and a lot of CheeseFactor :).

After a fresh restart, simplifying the problem domain and applying recursive heuristics the solution is indeed simple. And as simple as they are, i often wonder why/how/where the connection points get missed? Methinks the language of function within the education process is not as sufficient as it could be, but that’s another discussion. So, in summary:

• Always load your dynamic controls, even on the postback. The (!IsPostBack) is not an decision you can use for deciding to load controls dynamically. Use that for binding data.
• Page dynamically loads control inside OnInit(). By the time you hit Page_Load, it’s too late for anything viewstate related, particularly when we’re looking at nested, nested controls.
• Give your dynamically created controls a unique ID. Better for debugging so instead of trying to figure out the tree through reading _ctl1, _ctl2, etc.. The tree now reads as Main, Layout, View, Function, etc… Write code for programmers, not for computers.
• Immediately add the dynamic control to the tree before setting any properties on it.
• With dynamically nested controls, follow similar principles as for page. Don’t dynamically load a nested control inside ControlLoad. Too late. CreateChildControls works much better.

Following these guidelines, your nested, nested controls maintain viewstate perfectly with no additional plumbing. Including all repeater items containing additional server controls and other custom usercontrols.

Tools, Ideas and References:
Google
Concrete Mathematics, A Foundation For Computer Science, Graham, Knuth & Patashnik
dotnet247.com
Authoring Custom Controls
Dynamic Web Controls, Postbacks, and View State By Scott Mitchell

Categories
Technology

DataBinding on ASP.Net

After consideration from a previous post, i decided to boldly test my new class designs by making those private instance variables public. Beyond struggling against my own niggles, i discovered that ASP.Net doesn’t like breaking PrivateInstanceVariableMandate either. Consider the DataBinder for example.

In your mark-up code, a “typical” repeater section might look like


The DataBinder.Eval however only evaluates properties of that object. Public fields [class variables] are not properties and so breaking with traditions and trying to make things simpler, proved to be more complicated down the line [on this framework].

With a little co-ercion, it’s easy enuff to write a FieldBinder


to allow code such as above. All of a sudden i can access fields and it’s all good. Now the pro’s and con’s of introducing FieldBinder into the system can be debated at length, but the beauty of this insight led me to an even more interesting possibility.


There are times when real-time data associated with an object needs to be retrieved. Making the function a property, in a no-argument case, again, is a design preference but can lead to problems since the property EmailCount conveys a different sentiment to the method GetEmailCount(). The method, for me in my current project, implies that more work is done to retrieve the value than simply looking at one of the already present values. So i really want to keep it a function but can’t bind to it using DataBinder.

Extending this idea further, you can overload FunctionBinder to accept specific parameter types or arrays of objects for the function arguments. How you do that, well, that’s your decision…

SourceCode