Svelte asp.net: avoiding <form runat="server">

Postbacks in ASP.NET have a pretty heavy cost in terms of page size. Add a <form runat=”server”> tag and now you have a big ugly viewstate tag to lug around each time you load a new page. Put in a control that triggers postback (like a linkbutton) and suddenly there’s a big chunk of script and hidden fields where your nice simple form tag used to be:

  1. <form name="form1" method="post" action="Default.aspx" id="form1">
  2. <div>
  3. <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
  4. <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
  5. <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
  6.    value="/wEPDwUKLTkzNjc3NzczOWRk3iDWotjQ89h26Tx79TM3SRLPJlg=" />
  7. </div>
  8. <script type="text/javascript">
  9. //< ![CDATA[
  10. var theForm = document.forms['form1'];
  11. if (!theForm) {
  12.     theForm = document.form1;
  13. }
  14. function __doPostBack(eventTarget, eventArgument) {
  15.     if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
  16.         theForm.__EVENTTARGET.value = eventTarget;
  17.         theForm.__EVENTARGUMENT.value = eventArgument;
  18.         theForm.submit();
  19.     }
  20. }
  21. //]]>
  22. </script>
  23. <div>
  24.     <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
  25.         value="/wEWAgLAqu2HBQKfwImNC6GfmgtYoNIWKohd9XTK5tBa39eY" />
  26. </div>
  27. </form>

This is fine for a page that actually takes advantage of ASP.NET’s page lifecycle and controls, but can often be overkill for simple content driven applications that just need a little bit of server side logic. The good news is that in these cases you can have your serverside logic and eat it too just by using a simple html form tag with a regular GET request

Before – markup only a mother could love

The place I first thought of this was the search box on my old ASP.NET blog. Most of the pages on my blog were just straight content pages that didn’t need any of the postback logic. It seemed a real shame to add all this weight and complexity to the page just for a simple search form.

My search form was originally an ASP.NET form element with a button and textbox control that I could extract the search information from:

  1. <form id="form2" runat="server">
  2.     <asp :TextBox id="KeywordsField" runat="server" />
  3.     <asp :Button ID="SearchButton" Text="Search" runat="server"
  4.         onclick="SearchButton_Click" />
  5. </form>

The logic of redirecting to the search results page was a button click event with a Response.Redirect() call:

  1. protected void SearchButton_Click(object sender, EventArgs e)
  2. {
  3.  Response.Redirect("search.aspx?keyword=" +
  4.      Server.UrlEncode(KeywordsField.Text));
  5. }

The form HTML generated by ASP.NET looked like this:

  1. <form name="form2" method="post" action="Before.aspx" id="form2">
  2. <div>
  3. <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
  4.     value="/wEPDwULLTE0MDM4MzYxMjNkZB1GP1nffovgibqQWwhMKnQYMzMu" />
  5. </div>
  6.  
  7. <div>
  8.  <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
  9.             value="/wEWAwLtu4u/AQLfh7nDDALR1viaCYZVWJZuOfJe5p1cdkVMqJHz7Q3T" />
  10. </div>
  11.  <input name="KeywordsField" type="text" id="KeywordsField" />
  12.  <input type="submit" name="SearchButton" value="Search" id="SearchButton" />
  13. </form>

After – no server side code needed at all

All the markup seemed like overkill to me so I switched the form with a regular HTML form element (minus the runat=”server” attribute). Then I replaced the textbox and button controls with their HTML equivalents:

  1. <form action="Search.aspx" method="get">
  2.     <input name="keywords" type="text" />
  3.     <input type="submit" value="Search" />
  4. </form>

Complete example

Now my search form doesn’t need code behind logic at all! The action=”search.aspx” attribute of the form tag tells the browser exactly where the information should be redirected to. The method=”get” part tells it to send it on the query string. The name of the form fields are used as the query string key. In my case the search page was expecting a query string parameter called keywords so the text field’s name also had to be set to “keywords”.

So when the search button was clicked, the browser would try to load the following url (exactly what my old redirect was loading):
http://mysite.com/search.aspx?keywords=hello+world

The html generated now is still the same svelte markup I started with:

<form action="Search.aspx" method="get">
    <input name="keywords" type="text" />
    <input type="submit" value="Search" />
</form>

Note: it’s important not to put a runat=”server” attribute on the form fields because ASP.NET will change the name of the fields to something that’s guaranteed to be unique on the page. This is fine when you are using the fields in a postback but may mean that the values passed to the next page won’t have the right names.

For Barry :)

Q: why not just use Microsoft’s MVC framework so you never have to use postbacks?
A: You don’t always get to choose what you’re going to develop in and there’s an awful lot of WebForms code out there already that sometimes you just have to work with. :)

Posted on 08 Feb 09 by Helen Emerson (last updated on 08 Feb 09).
Filed under ASP.NET