Creating a RESTful Web Service Using ASP.Net MVC Part 11 – Supporting Incoming XHTML

November 21, 2008 01:05 by admin

In my last post we added functionality to the web service to accept incoming representations in the form of a PUT request. At the end of that post I admitted I hadn’t implemented the functionality to accept an incoming XHTML representation. The problem was with parsing a string of XHTML using .Net’s built in XML parsers. Loading XHTML straight into an XmlReader causes either an, “An error has occurred while opening external DTD” or a, “Reference to undeclared entity” exception.

In this post we’ll crack that problem.

The Problem

A typical XHTML file would look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>

    <title>Product clothing3</title>

    <link href="../Content/Site.css" rel="stylesheet" type="text/css" />

</head>

<body>

    <div class="page">

        <div id="main">

            <dl id="E6E8163F-6911-40E9-B740-90E5A0A3A996" class="product">

                <dt>name</dt><dd>clothing3</dd>

                <dt>category</dt><dd>Clothing</dd>

                <dt>details</dt><dd>Lorem ipsum dolor</dd>

            </dl>

            <div id="footer">&copy; Copyright Piers Lawson 2008</div>

        </div>

    </div>

</body>

</html>

Loading this into an XmlReader creates two issues. Firstly the DOCTYPE declaration informs the XML parser where to download additional grammar instructions. These instructions specify the permitted form of the rest of the document. If the parser is not preloaded with details of the specified DOCTYPE declaration it will need to download it. The URI contained in the DOCTYPE declaration indicates where the document can be found. The XmlReader in the .Net framework is not preloaded with this Document Type Declaration (DTD) so attempts to download it. Obviously, this is not particularly efficient! But worse, the URI above actually results in a redirect that the built in DTD resolver cannot follow. This results in the exception:

An error has occurred while opening external DTD 'http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd': The remote server returned an error: (300) Ambiguous Redirect.

So what happens if we simply discard the DOCTYPE declaration? Then we hit the second problem. Basic Xml only specifies a few “Entities”. Entities are those characters that are represented within an escape sequence such as &nbsp; for non-breaking space. Xml predefines:

  • &quot;
  • &amp;
  • &apos;
  • &lt;
  • &gt;

So when an XML parser hits the &copy; in the above XHTML fragment it doesn’t know how to cope with it. The XmlReader class throws an exception reporting:

Reference to undeclared entity 'copy'.

Which is correct… &copy; is declared in the DTD we have just thrown away! It would be nice if a flag on the XmlReader could tell it to be tolerant of undeclared Entities… then again that would not be very standards compliant!

So really, to work well with XHTML we should allow XmlReader to load the XHTML DTD.

Providing the XHTML DTD

How do we ensure the XmlReader has easy access to the DTD? XmlReader allows you to provide an XmlResolver object. The reader will ask the XmlResolver whenever it needs to access a URI, for instance when it needs to download a DTD. The default implementation will attempt to download the DTD from the actual URI. If we write our own XmlResolver, it can read the DTD from a resource.

With the release of SilverLight 2.0, Microsoft provided an XmlPreloadedResolver. This is a ready made XmlResolver that already has some DTDs built in. Just what we need! Only there are at least two snags:

  • XmlPreloadedResolver supports XHTML 1.0, not XHTML 1.1 which our web service uses;
  • Currently it is only part of the SilverLight 2.0 SDK and cannot be used by the full .Net framework (though the comments on the Microsoft XML Team's WebLog indicate they are looking at adding it to the next version of the framework).

So I rolled my own. I have to confess I took a lot of inspiration from SilverLight’s XmlPreloadedResolver… I basically created a cut down version. One issue I found was how to include the DTD in the resources. The standard XHTML 1.1 DTD is actually module based, i.e. it just contains a lot of links to sub-sections held in separate files. If I used this version of the DTD I would have to embed all the sub sections individually. In his Code Project article, Jinjun Xie bravely sets out to do just that, so hats off to him! I on the other hand decided to embed the single file, flattened version of the DTD.

I found one issue with the flattened DTD I downloaded…. it appeared to have two too many characters at the end, so couldn’t be parsed. After removing the last two characters everything started to work! Once the custom XmlResolver was added to the XmlReader and an ItemXhtmlExternalToInternal transform was written, our web service fully supported incoming XHTML representations.

So, notes about this implementation. Firstly, the cut down XmlPreloadedResolver could be removed if a future version of the full .Net framework contained its own version. Secondly, perhaps using the full, flattened DTD is not the most performant solution. Perhaps the module based approach means only those sections that need to be loaded are loaded. Another approach I have seen on the web is to only include the Entity declarations within the DTD… but I’m not so keen on that in case some other feature causes the XmlReader to throw an exception.

Anyway, you can judge for yourself as here is the code written in C#: RESTfulMVCWebService09.zip (75.48 kb)

My next entry in this series should tackle the POST HTTP verb.


Comments (3) -

December 3. 2008 22:07

Rafael Rosa Fu

Hi,

Nice series of posts. I'm working with ASP.NET MVC for sometime and now I'm thinking about some ways to connect it to a Ruby on Rails application, and RESTful services seems to be the way to go. I'll make some experiments with your code and them all get back to you. Thanks for the good info.

Cheers,
Rafael.

Rafael Rosa Fu

September 30. 2009 13:23

google-earth

Creating a RESTful Web Service Using ASPNet  , raised my curiosity. I have recently started out to develop using Silverlight but  am finding it is a real learning curve.  My recent experience is with mysql, php, most linux based tools and flash. The ambition of applying Silverlight to produce a good page which functions speedily in all the leading web browsers, Internet Explorer, Firefox, Safari and Chrome can be a big headache that I find is taking umpteen hours to overcome.  Absorbing to read your thoughts and the comments in your website on Silverlight.  I feel the tutorial web sites and Microsofts offering are inert and cover the same points, comments and dialog in web logs oftentimes references actual ways to beat problems that leads me through the learning curve more rapidly.  Thanks for the post, it has helped in a small way to get me through the migration.

google-earth

April 9. 2010 10:03

Definitely

Hi just thought i'd inform you some thing. This is the second time now i have landed in your weblog in the last four days hunting for totally unrelated points. Spooky or what?

Definitely

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading