Serving the Correct MIME Type for XHTML using ASP.NET 2.0

This example code goes some way to serving XHTML properly, as outlined in the article: Serving the Correct MIME Type for XHTML.

Idealy, text/html should only be served when the user agent specifies acceptance of text/html, but not application/xhtml+xml. However, Internet Explorer 6 does not return anything useful in it’s HTTP_ACCEPT response.

Place the following code in the Page_Init section of your master page:

String strContentType = null;
// Determine if the user agent returns any AcceptTypes (HTTP_ACCEPT) response
if (Request.AcceptTypes != null)
{
  // Determine if the user agent can handle XHTML served as "application/xhtml+xml" (e.g. FireFox, Opera)
  if (Array.IndexOf(Request.AcceptTypes, "application/xhtml+xml") > -1)
  {
    strContentType = "application/xhtml+xml";
  }
  else
  {
    // If the user agent does not specifiy acceptence of "application/xhtml+xml", then serve as "text/html" (e.g. Internet Explorer)
    strContentType = "text/html";
  }
}
else
{
  // If AcceptTypes is null, then serve as "application/xhtml+xml" (e.g. W3C Validator)
  strContentType = "application/xhtml+xml";
}
// Set the Response Content Type
Response.ContentType = strContentType.ToString();
if (strContentType == "text/html")
{
  // Generate a "content-type" meta tag in the page head
  HtmlMeta hmtContentType = new HtmlMeta();
  hmtContentType.HttpEquiv = "content-type";
  hmtContentType.Content = strContentType.ToString() + "; charset=UTF-8";
  Page.Header.Controls.Add(hmtContentType);
}
else
{
  // Generate xml declaration
  Response.Write("<?xml version="1.0" encoding="UTF-8" ?>
");
}
// Set the page encoding
Response.ContentEncoding = System.Text.Encoding.UTF8;
// Send a Vary header to inform proxy servers that content negotiation is taking place
Response.AddHeader("Vary", "Accept");

Note

When served as application/xhtml+xml, all <style> and <script> in the XHTML document must be marked as CDATA. Because ASP.NET automatically generates JavaScript, this can be a problem. See Marking ASP.NET 2.0 Generated JavaScript as CDATA for a workaround.

Marking ASP.NET 2.0 Generated JavaScript as CDATA

The following code example is a workaround for marking ASP.NET generated JavaScript as CDATA, which is required when serving XHTML ASP.NET 2.0 pages as application/xhtml+xml (see Serving the Correct MIME Type for XHTML using ASP.NET 2.0).

Place the following code in your master page:

protected override void Render(HtmlTextWriter writer)
{
  StringWriter stwHtml = new StringWriter();
  base.Render(new HtmlTextWriter(stwHtml));
  String strHtml = stwHtml.ToString();
  // Enclose ASP.NET generated client ECMAScript / JavaScript in CDATA Wrapper
  Regex regScriptCDATA = new Regex("(<script\stype="text\/....script">(?:\s)*?)" + "(?:<!--\s)" + "((?:.|
)*?)" + "(?:// -->)" + "((?:\s)*?<\/script>)");
  String strScriptCDATA = "$1" + "<!--//--><![CDATA[//><!--
" + "$2" + "
//--><!]]>" + "$3";
  strHtml = regScriptCDATA.Replace(strHtml, strScriptCDATA);
  writer.Write(strHtml);
}

You may need to add the following at the beginning of your master page code:

using System.IO;
using System.Text.RegularExpressions;