There has been a backlash of articles on serving XHTML with a proper Content-Type header. Having read documentation and blog posts on this saga I decided to try this out for myself since I do my best to serve proper XHTML here.
If you're not sure what I'm talking about and what the fuss about application/xhtml+xml is check out the following links for a helpful introduction to this subject (listed in the order of importance):
If you DID follow these links you know that serving XHTML as text/html pretty much defeats the purpose of authoring XHTML since it will be treated as HTML anyway. On the other hand, serve your content as application/xhtml+xml and Internet Explorer will blow up, while "conforming" browsers will attend to it as the spec says. To serve two masters we need to feed the good ol' text/html to IE, and application/xhtml+xml to Mozillas and Operas of the world.
Back when I published my findings on Unicode in VS.NET 2003 I alluded to the fact that you can highjack content type.
The trick is to change it before the headers and written out. I thought of my favorite way of handling such tasks: HTTP modules. One of the "nondeterministic" events an HttpModule fires is PreSendRequestHeaders. The even "occurs just before ASP.NET sends HTTP headers to the client." Perfect. This much accomplishes it:
public class ContentType : IHttpModule
{
public void Init(System.Web.HttpApplication application) {
application.PreSendRequestHeaders +=
new EventHandler(this.Application_PreSendRequestHeaders);
}
private void Application_PreSendRequestHeaders (object sender,
System.EventArgs e)
{
HttpApplication app = ((HttpApplication)(sender));
HttpContext context = app.Context;
if (context.Request.Browser.Browser.ToUpper ().IndexOf("IE")==-1)
context.Response.ContentType = "application/xhtml+xml";
}
public void Dispose() {}
}
I used my own Template Generator For HttpModules and HttpHandlers to create skeleton code of this HttpModule. All it does is look at the browser string submitted in the User-Agent header. There's no else statement since by default HttpResponse assigns text/html to its private member.
public HttpResponse(TextWriter writer)
{
this._statusCode = 200;
this._bufferOutput = true;
this._contentType = "text/html";
...
}
Feeling of Remorse
As of today, all pages on this site are served as application/xhtml+xml to all browsers but IE. I'm willing to experiment. To be honest, this exercise puts me on the edge of my seat because a minor slipup in "well-formedness" and the page doesn't render (this is XML after all, so it "functions as designed"). The power of ASP.NET lies in delivering killer functionality to a developer and hiding all the plumbing. I just hope I lay out the plumbing right and nothing leaks.
We'll see how it goes. If anyone notices a catastrophe please shoot me an email.
August 3, 2004: I've changed the code above as suggested by Charl (see comments). This time around I check if the user agent accepts 'application/xhtml+xml'.