Wow. My post on ASP.Net and standards seems to have touched a nerve. I received a pile of feedback via email on that one, and with a currently crazed work schedule it’s taken me until now to sort through all the good info provided.

The upshot: yep, ASP.Net’s built-in functions are tone-deaf when it comes to standards. And yep, there are irritating restrictions on <form>s in ASP.Net. But the latter aren’t so bad as they seem, and the former are slated to be addressed in ASP.Net 2.0, which should be along Real Soon Now.

The Form Thang

Phil Baines notes that while there is no requirement to put the entire page in a <form> tag, there is an irksome ASP.Net limitation regarding <form>s: only one per page can use ASP.Net’s custom validation and the like.

According to Rick Mason, Web Technical Officer for East Essex County, this is due to the way Microsoft has chosen to maintain state across form submissions. When a user submits a <form> with an error, ASP.Net automagically returns the <form> to the user with the user’s input still in place.

That’s a very good thing for <form> usability. What maybe isn’t so good is that Microsoft implemented this functionality by adding a hidden <input> called _VIEWSTATE. The way that is implemented precludes using more than one <form> per page, thereby making it necessary to wrap every element whose state is to be maintained in a single <form> tag.

While this requirement doesn’t do anything good for document semantics, it’s really not the end of the world, and in any event is to be addressed in ASP.Net 2.0.

Invalid Validators

Milan Negovan of ASP.Net Resources, a site dedicated to using ASP.Net and web standards (bookmark!), does a great job demonstrating the problems ASP.Net’s built-in controls create when trying to create valid XHTML (real XHTML, with an application/xhtml+xml MIME type and everything) or even just HTML (BTW, be sure to read to the end for his thoughts on the suitabilty of XHTML for web applications).

It gets worse, though. According to Milan, ASP.Net has a notion called ‘adaptive rendering.’ The idea is that ASP.Net will automagically write markup tailored to the specific user agent requesting the page. Setting aside for a moment the fundamental stupidity of UA-based markup switching, there’s still a problem with the implementation: it considers every browser but IE/Win to be ‘downlevel’ (‘old and crippled’, in the parlance of our time) and serves them up crufty ol’ HTML 3.2. Ironic, no?

To be completely fair, ASP.Net was under development right around the turn of the century. Back then, the main ‘alternative’ browser was Netscape 4.x, which was most definitely ‘downlevel’ in anyone’s book. But that’s cold comfort to those of us developing web pages today.

For this reason, Rick echoes Nick Vrillo’s sentiments that creating custom controls is the way to go, and notes that ASP.Net’s HtmlGenericControl is mighty helpful in this respect.

What HtmlGenericControl does is allow you to manipulate the contents of an elment via ASP.Net. All you do is insert an id and the ASP.Net attribute runat="server" (don’t get your panties in a wad — it’s removed before the page is sent to the browser) and away you go.

Useful, but it seems as though it’d be more useful if it didn’t rely on an id and could therefore use more than one such control per page.

Other Odds & Sods

Phil has also posted a mini-rant about the difficulties of developing to web standards in Visual Studio 2003. Phil is particularly frustrated by Visual Studio’s insistence on changing the formatting of his source code, a glitch whose source is explained by Mikhail Arkhipov in a blog post.

Peter Ankelein also wrote in to express his frustration with ASP.Net’s postback. Postback is Microsoft’s term for when an ASP.Net <form> assigns its action attribute to itself, so the <form> gets submitted to itself. This is common practice in PHP as well, and in most instances it’s a pretty useful trick. However, ASP.Net apparently forces this behavior unless you jump through hoops to avoid it. That makes things like posting <form> input both to a local database and to a remote handler more difficult than it ought to be.

What does that have to do with standards? Not much, except that it’s a great example of why it’s a Bad Idea to subvert standard attibutes and elements. By appropriating the action attribute of the <form> tag, Microsoft has altered its functionality and made things that should be easy less so.

While you’re in a reading mood, be sure to read to the bottom of Milan Negovan’s post for some interesting thoughts on the suitabilty of XHTML for web applications.

Summing Up

While ASP.Net is a powerful, and in many ways convenient, server-side scripting language, its fundamental philosophy can make life unnecessarily difficult for standards-aware web developers.

For starters, Microsoft has ‘integrated’ markup with the language by appropriating attributes like id and the <form> tag’s action. While it’s certainly a far cry from the mishmash of server-side code and markup that characterized old-skool ASP or much of the PHP out there, there are times when this integration turns around and bites the very developers it’s supposed to help.

More fundamentally, ASP.Net still views markup as primarily a presentation tool. Even when generating markup for ‘uplevel’ browsers, it just substitutes <span> for <font> and <div> for <table>. That might have made sense back in the bad old tag soup days, but today there’s a better way. Keeping document structure separate from style pays big dividends in page weight, flexibility and maintainability. By working against this separation, ASP.Net again complicates the lives of the very developers at whom it is aimed.

Likewise, ASP.Net attempts to work around browser incompatibilities via the discredited technique of browser-sniffing. Browser sniffing is attractive in some cases, and in fact most CSS hacks are just a sophisticated form of browser sniffing. However, the fact remains that when you go down that road you’re practically begging for your code to break when a new browser arrives. More, you dramatically increase the complexity of your code as you try to keep straight all the browsers, versions and micro-versions around.

A more flexible and robust approach is to sniff for browser capabilities, and then write to those. That’s easier to do on the client side than on the server, of course. But good defensive coding practices like WaSP project leader Steven Champeon’sprogressive enhancement can minimize the frustration.

The Future

Virtually every person responding to my post made a point to say Microsoft has seen the error of their ways — at least as far as ASP.Net’s standards-unfriendly behavior is concerned. They’ve promised to rectify all of the frustrations listed above, and then some.

While we won’t know what actually gets addressed and how until Microsoft actually releases the final ASP.Net 2.0 engine, I’m optimistic that ASP.Net will soon be as strong a platform as there is for developing standards-compliant web sites.

Update: Paul Watson of the Bluegrass Group has written in to tell me my newbie is showing.

Apparently, the id attribute on an ASP.Net custom tag (AKA ‘custom control’) is just an instance name. That is, it’s a handle to identify a unique (as in one and only one) occurence of the control in an ASP.Net page — rather like an id attribute on an HTML tag identifies a unique occurance, or ‘instance’, of that tag on a page. So Microsoft looks to be doing the Right Thing there (some folks may wish to debate whether server-side code should pay any attention at all to attributes that are meaningful on the client side; I’m not one of ‘em).

What identifies which code defines the behavior of a custom control, then? Well…thereby hangs the tail of a cat, it would seem.

The short answer is that custom controls are defined by the tag name + prefix, which looks something like: <chris:MySuperControl>, which looks an awful lot like an XMLnamespace. But it isn’t. At all. Let’s put a stop that rumor, right now.

What it is, is a tag prefix (in the example above, chris) and a tag name (in the example above, MySuperControl). From there, things get a mite hairy. I’ll let Paul explain:

When you want to include a custom control in your ASPX page you have to tell ASP.NET to expect custom control tags in your HTML. You do this using <%@ Register TagPrefix="chris" TagName="MySuperControl"
Src="SuperControl.ascx" %> right at the top of your ASPX file.

May be blindingly obvious, but; SuperControl.ascx is your custom control code file. It is the only bit which has to map through to something, in this case a physical file. The TagPrefix is the bit before the : and the TagName is the bit after the :. The latter two don’t have to have any correlation to what is inSuperControl.ascx though it makes sense to use the same name.

If you have two different custom controls then you would have that declaration twice. The TagPrefix could stay the same but the TagName and the src will have to be unique. If you have three custom controls then you need three declarations, and so on.

It gets even more confusing when you consider there are two levels of custom control. The ASCX type I mentioned above and then a more abstracted type which comes straight from a C#/VB.NET class file. E.g.
SuperControl.ascx would normally have an associated SuperControl.ascx.cs file; that is the code-behind file which contains the logic of the control. But with the second type of custom control you wouldn’t have the .ascx file at all, you just have a SuperControl.cs file. With the latter type you use a different declaration to tell ASP.NET to expect custom control tags and in this case the TagName will map to the class name so it can’t be anything you like. The TagPrefix can still be whatever you like though.

asp:TextBox and other built-in ASP.NET controls are treated slightly differently in that you don’t need to tell ASP.NET what tags/prefixes to expect in the ASPX file. Strangely asp: is not reserved to built-in controls. I just did a custom control and used asp: as the prefix and it worked fine. I wouldn’t normally do that though so as to distinguish custom controls from built-in.

So there you have it.

Now, if you’ll excuse me I’m going to go grab some pepto to quell that queasy feeling I got from reading that Microsoft is employing a syntax that looks just like a significant part of the XML standard (albeit a controversial one), but is actually completely different. I’m sure there’s a reasonable explanation, and I’m not at all sure what they’ve done actually hurts anything, but it makes me uneasy nonetheless.