A Look at ASP.NET's Adaptive Rendering
By Scott Mitchell
Introduction
ASP.NET Web pages, as you know, are made up of an HTML portion and a source code portion. The HTML portion contains a mix of HTML markup along with Web controls. When the ASP.NET Web page is visited, the Web controls are rendered into HTML markup. The static HTML markup, along with the rendered Web controls markup, is sent back to the visitor that requested the page, and displayed in their browser.
The HTML rendered by Web controls, though, depends on the browser requesting the ASP.NET Web page. For this reason,
ASP.NET Web controls are called adaptive. For example, if a visitor requests a page using Internet Explorer 6.0,
they'll receive HTML 4.0-compliant markup; for example, a Label Web control whose ForeColor
property were
set to Red would render the following markup:
<span id="controlID" style="color: red">Label Text</span>
|
If, however, the same visitor were to use Netscape 4.72, they'd receive
HTML 3.2-compliant markup. The HTML for the Label Web control would specify the color using a <font>
element rather than a style
attribute in the <span>
.
<span id="controlID"><font color="red">Label Text</font></span>
|
While adaptive controls are a nice concept in general, ASP.NET's default implementation can be a bit frustrating since for modern browsers - such as recent versions of Mozilla, Firefox, Netscape, and Opera - ASP.NET controls render, by default, HTML 3.2-compliant HTML rather than HTML 4.0-compliant HTML. Fortunately, you can configure your Web application (or the entire Web server) to render HTML 4.0-compliant HTML for these modern, non-Microsoft browsers. In this article we'll see how ASP.NET decides whether to render the Web control HTML as 4.0-compliant or 3.2-compliant. We'll also look at how to configure your Web application so that modern versions of Netscape, Opera, and Mozilla cause ASP.NET to render 4.0-compliant markup.
How Web Controls are Rendered
Each and every ASP.NET Web page is derived either directly or indirectly from the
System.Web.UI.Page
class.
This class provides the base methods and properties that represent an ASP.NET Web page. Whenever a request is received
by the Web server for an ASP.NET Web page, Web server hands off the request to the ASP.NET engine, which creates an
instance of the requested page's Page
class and calls this class's ProcessRequest()
method.
The call to the ProcessRequest()
method kicks off the page's life cycle, which involves loading the page's
control hierarchy, restoring the view state, firing the Load
event, firing Web control events, saving the
view state, and rendering the page. The diagram below graphically illustrates the ASP.NET page's life cycle. (Click
here for a larger view...)

The specifics of this life cycle are not important to this article, but if you're interested in learning more might I suggest reading How ASP.NET Web Pages are Processed on the Web Server and The ASP.NET Page Object Model.
The ASP.NET Web page is rendered in the following manner: the Page
class creates an instance of a
System.Web.UI.HtmlTextWriter
class, and then recursively calls the RenderControl()
method
of all of the controls in its control hierarchy, passing in the HtmlTextWriter
instance. Each control,
then, appends its HTML markup to the end of the same HtmlTextWriter
instance. After all controls have
been rendered, the Page
class can return the entire page's HTML markup by returning the content in that
HtmlTextWriter
instance.
Adaptive Rendering with HtmlTextWriter
The
System.Web.UI
namespace contains two classes for rendering Web controls: HtmlTextWriter
, which
renders HTML 4.0-compliant markup, and Html32TextWriter
, which renders HTML 3.2-compliant markup. (The
Html32TextWriter
class is derived from the HtmlTextWriter
class.)
When the Page
class enters its render stage, it starts by creating a new HtmlTextWriter
instance. It determines what class instance to create - HtmlTextWriter
or Html32TextWriter
-
by inspecting the TagWriter
property of the Browser
object. The Browser
object
contains read-only properties that provides information about the browser that was used to request the ASP.NET Web page.
A Web browser is identified by its User-Agent string.
Whenever a Web browser requests a page, it sends along
a User-Agent string in the HTTP headers that is used to identify the browser. Internet Explorer, for example, sends
the User-Agent string Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)
.
Mozilla FireFox sends the User-Agent string Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8
.
Some browsers don't send a User-Agent string, or send a "fake" User-Agent string. For example, with Opera you can instruct it
to send the IE6 User-Agent string. There's an extension
for Mozilla that offers the same functionality as well. (Interested in seeing what User-Agent string your
browser is sending? Check out the
User-Agent live demo.)
The ASP.NET engine examines the User-Agent string to determine the values for the Browser
's properties.
One of the properties is TagWriter
, which, by default, is set to HtmlTextWriter
for Internet
Explorer 4.0 and up. For all other browsers, it is set to Html32TextWriter
. Fortunately, these settings
are configurable, so you can indicate that modern versions of Netscape, Mozilla, and Opera use the HtmlTextWriter
class as opposed to Html32TextWriter
. These settings can be made through the <browserCaps>
section in either the maching.config
or Web.config
files. (Altering the settings in
maching.config
will set the default behavior for all Web applications on the Web server. To control
the settings on an application-by-application basis, use the Web.config
file.)
Examining the <browserCaps>
Element
The
<browserCaps>
element contains a number of <case>
elements. Each of these
<case>
elements has a match
attribute, which contains a regular
expression. If the regular expression matches with the User-Agent string sent by the browser, the properties inside
the <case>
element are applied to the Browser
object. If you look in the machine.config
you'll see that, by default, the TagWriter
property is set to the Html32TextWriter
class:
<browserCaps>
|
Further down, you'll find a <case>
element that matches Internet Explorer's User-Agent. Here,
you'll find that the TagWriter
property is set to the HtmlTextWriter
class:
|
For non-Microsoft browsers, the TagWriter
property remains the default - Html32TextWriter
.
Configuring HTML 4.0-Compliant Rendering for Netscape, Mozilla, and Opera
Before we examine precisely how to configure the
maching.config
or Web.config
files so that
modern, non-Microsoft browsers render HTML 4.0-compliant markup, let's first discuss the motivation behind this.
You may be wondering why go to this trouble. After all, while ASP.NET may render a Label with a red ForeColor
as <span id="controlID" style="color: red">Label Text</span>
, and render the
same Label as <span id="controlID"><font color="red">Label Text</font></span>
for Netscape users, in the end, they see the same thing, so what's the big deal?
Well, for the ForeColor
, yes, this is the case, but if you set the BackColor
property on a
Label the HtmlTextWriter
class uses the background-color
CSS setting to specify a background color.
Since there is no way to set a background color for an HTML element without CSS (short of using a <table>
or some
other trickery), the Html32TextWriter
class simply ignores the BackColor
property. In addition
to this reason, another motivation behind 4.0-compliant markup is that the HtmlTextWriter
class can render
<div>
elements; the Html32TextWriter
class renders <div>
as
<table>
s. This can cause some oddities
for certain scenarios.
The following shows the <browserCaps>
section you can add to your Web.config
file
to specify that modern, non-Microsoft browsers cause the Web controls to render HTML 4.0-compliant markup. Notice that
in addition to setting the TagWriter
property, the <browserCaps>
section below also
sets a number of other properties for the Browser
object. (This
<browserCaps>
section was created by Rob
Eberhardt, and is available here.)
<!-- 2003-12-03, Rob Eberhardt - http://slingfive.com/demos/browserCaps/ -->
|
Moving Forward - Client-Side Validation
While configuring ASP.NET to render HTML 4.0-compliant markup for users surfing with modern versions of Netscape, Opera, and Mozilla is a good first step, you might be disappointed to find out that even with this change, the validation controls still won't render client-side validation script. There are a couple of (annoying) reasons for this, but I'm going to save this discussion for a future article!
Until then, Happy Programming!
An Article on Client-Side Validation |
---|
I have authored an article discussing why client-side validation doesn't work in downlevel browsers, along with a discussion on how to implement client-side validation. Learn more at Client-Side Validation in Downlevel Browsers |