Controlling HTML in ASP.NET WebForms
Listen to the Show!
Resources Mentioned in the Show
- Interview with Scott Guthrie
- ASP.NET SEO
- BookRepository
- Implementing Ajax Live Form with NetAdvantage Controls
Developers want control. Developing for the web is seemingly more of a love/hate relationship with the tools at our disposal. Sometimes our tools and frameworks give us power, but not control. While we love the functionality and ease-of-use of many of the stock server controls found in ASP.NET WebForms, sometimes we find that the underlying HTML isn’t exactly what we need.
To address the growing need for more control over web page markup we’ve seen movements like the CSS Control Adapters and the emergence of ASP.NET MVC framework which give us 100% control over markup.
MVC and control adapters are not the only answer to gaining more control. For the sea of standard WebForm applications there are many techniques available for gaining more control.
Tame ViewState
One of the first places to exercise control over your HTML is to reign in ViewState. ViewState was once hailed as a huge time saver upon its introduction and now often the bedrock feature of ASP.NET is maligned for all manner of code bloat.
The fact is, though, ViewState is not inherently evil and is effective when used appropriately. The problem with ASP.NET is not that it features ViewState, but that the framework is cavalier in its use of ViewState. The problem is ViewState is turned on by default.
Consider a page that includes a data-bound ListView control using the default ASP.NET template. The page template and all controls automatically have ViewState enabled.
The following is a screen shot of the HTML generated by the ListView:
Notice that the control simply renders a table. There is no editing behavior implemented on this page therefore there is no need for ViewState. Disabling ViewState will change the source to look like this:
Note: Surprisingly, setting EnableViewState="false" does not get rid of ViewState entirely. If you have a HTML form set to run-at server, then you will always have at least one hidden control in your markup with some "ViewState" data. This data, though, is trivial in size.
Tip: Turn off ViewState by default and use it only when necessary. You can even turn off ViewState globally in your application by disabling it in the web.config in the pages element.
If you find ViewState is unavoidable in your application you may consider looking into the options of moving it to the web server or even down to the database.
Question the Form Tag
Another foundational control in ASP.NET is the run-at server form tag – but do you really need it?
As you just saw when working with ViewState, as long as a server-controlled form element is on your page, extra HTML in the form of ViewState and supporting JavaScript for post backs is emitted to the page. The default ASP.NET page template includes a form tag on every page, but often its presence is not necessary.
Returning to the example from the previous section, look at the HTML generated from placing a read-only ListView in a server form with ViewState disabled:
This page has no input controls and is simply a read-only page so having a form on the page doesn’t really make sense.
The next screen shot is how the page looks with the form tag removed:
Tip: Remove server-controlled forms from your page if they are not necessary.
You may even consider removing them from your page first and wait for the design to dictate whether or not you need a form on the page. Perhaps you are even so bold as to edit the Visual Studio template to remove the form tag from new pages?
The template is found under this location:
C:\Program Files\Microsoft Visual Studio 9.0\Web\WebNewFileItems\CSharp\WebForm.aspx
or
C:\Program Files\Microsoft Visual Studio 9.0\Web\WebNewFileItems\VB\WebForm.aspx
NOTE: If you edit this file you are tinkering with Visual Studio’s default templates, which under normal circumstances is probably a bad idea. The change suggested here, however is pretty benign. In any event make backups - be certain of what you are doing, and if something goes wrong don’t blame me :)
No-Markup Controls
Server controls are valuable because they create a layer of abstraction above HTML elements. This abstraction determines how controls render to different browser versions and save developers time from having to write code by hand. While these benefits are realized in many situations, sometimes server controls are just more than you need.
I have often seen developers use inappropriate controls just to get some text on the screen or to control the visibility of controls.
The Literal Control
Do you need to render a simple string to the page? Then don’t use a Label control unless you have plans for the extra SPAN tags that come with the data – instead try using a Literal control.
The Literal control’s purpose is to render a string literal to the page – and only the string literal.
Take a look at the next two lines of ASPX code:
The controls are effectively doing the same thing: rendering a name to the page. The resulting HTML from each of these controls is quite different:
The Label is rendered with wrapping SPAN tags. In this case, the control is on a page associated to a master page so the HTML bloats even further with the unique client ID generated by the server. Often when using a Label control developers do not use the accompanying HTML that’s rendered with the data.
Using the Literal control, however simply renders the text to the screen as desired.
Tip: Be aware of when you simply need text on the page and use the appropriate controls.
Note: Take care to not confuse the Literal control with a different control name LiteralControl.The LiteralControl exists to aid server control construction and is rarely used directly in code.
The Placeholder Control
Do you need to programmatically show or hide a group of controls? Don’t just make that DIV runat="server" or turn to a Panel control – instead try wrapping your controls in a Placeholder control.
The Placeholder control is a very useful control that doesn’t seem to get a lot of attention. What makes the Placeholder useful is that the control may contain children controls and it renders no HTML to the page.
Often Placeholders are used for template designs and other scenarios where you don’t know which controls are needed until runtime. There are a number of other applications for the Placeholder beyond its normal use. You can also use this control to help control what is shown and hidden on your page.
Consider the typical scenario where a message is initially hidden from the user, but is later displayed on the screen. A common approach to this problem is to create a server-controlled DIV on the page and set the Visiblity property to false:
For simple pages the markup that is rendered to the page is exactly what you would expect, but in more practical settings the HTML gets altered.
The next screenshot shows you how that DIV is rendered to the page when the markup lives inside a master page:
The age-old problem of ASP.NET changing a control’s ID creeps up. This is a problem because once you start interacting with style sheets and JavaScript the client IDs become very important. While there are a number of ways around this issue for both CSS and scripting, why not dodge the problem altogether?
Instead of making the DIV a server control, wrap your content inside a Placeholder and then you have the same programmatic control over the block of controls without having to worry about the HTML being affected.
You could also use the MultiView control to accomplish this same behavior without generating any extra markup.
Tip: Use controls that do not generate HTML wherever appropriate.
Expressions Have No Ego
If you truly don’t need extra markup created for you – consider skipping the use of a server control altogether and use in-line expressions. ASP.NET MVC makes heavy use of expressions and while some think heavy use can create messy co-mingled code – there is a good pragmatic reason for using them.
If you use a server control, you have to have some strategy for providing the control with data. Getting data into the control requires you to write code in the codebehind. Writing code is not a bad practice at all – it can just be time-consuming. Depending on where the control resides on the page you will often have to do most if not all of these steps:
- Declaring a control in the ASPX
- Finding the appropriate event method in the page lifecycle to tap into
- Locating and cast the control to the appropriate type (in some cases)
- Provide the control with data
If you opt for using expressions instead you can simply inject the data exactly where it need to go.
So instead of doing this:
Try doing this:
In the end you’ll find that not using server controls when they are truly unnecessary will help tame your rendered markup significantly.
Choose Controls Wisely
One of the best ways to control the HTML that your pages generate is to be familiar with what common controls with render. The following tables contain an abbreviated list of ASP.NET server controls and a summary of the type of markup they emit.
Standard Controls
Control Name | Renders |
---|---|
Label | SPAN elements surrounding Text property value |
TextBox | HTML text input element |
Button | HTML button input element |
LinkButton | Anchor element |
ImageButton | Anchor and image (IMG) elements |
HyperLink | Anchor element |
DropDownList | Select element with options for values |
ListBox | Select element with option tags for values. (The ListBox renders a value for the SIZE attribute allowing more than one option to appear at a time.) |
CheckBox | HTML checkbox input element |
CheckBoxList | If RepeatLayout is set to Table, then the control renders standard table markup with the checkbox input elements. If RepeatLayout is set to Flow, then the control renders a series of Label and BR elements with the checkbox input elements. |
RadioButton | HTML radio input element |
RadioButtonList | If RepeatLayout is set to Table, then the control renders standard table markup with the radio input elements. If RepeatLayout is set to Flow, then the control renders a series of Label and BR elements with the radio input elements. |
Image | IMG element |
ImageMap | IMG element and MAP element |
Table | HTML table |
BulletedList | Series of LI elements inside a UL element |
HiddenField | HTML hidden input element |
Literal | N/A |
Calendar | Complex series of elements including links and table markup |
AdRotator | Anchor and image elements |
Wizard | Complex series of elements including links and table markup |
MultiView | N/A |
Panel | DIV or Table element depending on the browser capabilities |
Placeholder | N/A |
Data Controls
Control Name | Renders |
GridView | Table element with optional anchors |
DataList | If RepeatLayout is set to Table, then the control renders standard table markup If RepeatLayout is set to Flow, then the control renders a series of Label and BR elements |
DetailsView | Series of elements including links and table markup |
FormView | HTML table |
Repeater | N/A |
ListView | N/A |
ASP.NET SEO
Much of the talk surrounding taming HTML is often in the context of building website to be search-engine friendly. In some arenas ASP.NET is viewed as a sub-standard platform for creating search engine optimized websites. While this charge is categorically false, sometimes it’s not hard to see why some reach such an extreme conclusion.
ASP.NET is no better or worse platform for building sites optimized for search engine placement than a Java or Rails site – the problem is often the UI developer. While Microsoft and a host of third-party organizations work hard building tools and controls that aid in RAD development, using these techniques in their default states, may not always be the best approach for building public facing websites.
The bottom line is know the HTML you are generating and use the right tool for the right job.