this is one of a series of short articles that describe how basic HTTP programming works with the exyus engine for C#. the aim of the exyus engine is to make it as easy as reasonably possible to create REST-compliant web applications using C# and ASP.NET.
this article focuses on how to define client views against an exyus resource object. in this example, i have been working with a simple products/categories data model that shows how to implement a very basic shopping web. in other posts on this topic, i've talked about how resource object are defined and how to implement them using the exyus classes in C#. now, let's do a quick review and move on to executing the views of a resource.
the first step is to define the resource you plan on presenting to clients. in this case, i created a simple
product
resource that has the following XSD Schema definition:
<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="product"> <xs:complexType> <xs:all> <xs:element name="id" type="xs:integer" minOccurs="1" maxOccurs="1"/> <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs ="1"/> <xs:element name="category" type="xs:string" minOccurs="1" maxOccurs ="1" /> <xs:element name="quantity-per-unit" type="xs:integer" minOccurs="0" maxOccurs ="1" default="1"/> <xs:element name="unit-price" type="xs:float" minOccurs="0" maxOccurs ="1" default="10.00"/> <xs:element name="units-in-stock" type="xs:integer" minOccurs="0" maxOccurs ="1" default="100"/> <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs ="1"/> </xs:all> </xs:complexType> </xs:element> </xs:schema>
the next step is to create a code class in exyus that will define the product
resource
as a valid HTTP resource object. that means establishing the 1) address (/data/products/), verbs (GET [for now]),
and the representations (text/html,text/xml
). below is the exyus resource object:
[UriPattern(@"/data/products/(?<pid>[^/?]*)(?:\?)?(?:[^/]*)?")] [MediaTypes("text/html", "text/xml")] public class productsResource : XmlFileResource { public productsResource() { this.ContentType = "text/html"; this.DocumentsFolder = "~/documents/products/"; this.StorageFolder = "~/storage/products/"; this.XHtmlNodes = new string[] { "//description" }; this.LocalMaxAge = 600; this.ImmediateCacheUriTemplates = new string[] { "/data/products/", "/data/products/{pid}" }; } }
now you get to the current fun - implementing the response representations. in this example, i chose to make
XHTML the default representation. that means i need to define a get_response_list_html.xsl
document (see figure 1).
here's what that looks like:
<?xml version='1.0' encoding='utf-16' ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" encoding="utf-16" omit-xml-declaration="no"/> <!-- root --> <xsl:template match="root"> <div class="products"> <xsl:apply-templates select="item" /> </div> </xsl:template> <!-- unfiltered list --> <xsl:template match="item"> <div class="product" seq="{position()}"> <h3 class="name"> <label for="id">name:</label> <a href="{document(./@dref)/product/name}" title="{document(./@dref)/product/name}"> <xsl:value-of select="document(./@dref)/product/name" /> </a> </h3> <p class="product-image"> <a href="{document(./@dref)/product/name}" title="{document(./@dref)/product/name}"> <img src="/xcs/products/images/{document(./@dref)/product/name}_thumb.jpg" /> </a> </p> <p class="id"> <label for="id">id:</label> <xsl:value-of select="document(./@dref)/product/id" /> </p> <p class="category-detail"> <label for="category">category detail:</label> <a href="categories/{document(./@dref)/product/category}" title="{document(./@dref)/product/category}"> <xsl:value-of select="document(./@dref)/product/category"/> </a> </p> <p class="unit-price"> <label for="unit-price">unit-price:</label> <xsl:value-of select="document(./@dref)/product/unit-price" /> </p> <p class="units-in-stock"> <label for="units-in-stock">units-in-stock:</label> <xsl:value-of select="document(./@dref)/product/units-in-stock" /> </p> <p class="quantity-per-unit"> <label for="quantity-per-unit">quantity-per-unit:</label> <xsl:value-of select="document(./@dref)/product/quantity-per-unit" /> </p> <p class="description"> <label for="description">description:</label> <xsl:value-of select="document(./@dref)/product/description" /> </p> </div> </xsl:template> </xsl:stylesheet>
i also need to implement the get_response_item_html.xsl
document to handle requests for a single
product. for brevity, i'll leave that one out for now (see figure 2).
note that i've also included hyperlinks in the list and item representations that point to other products and even category objects (not defined here, for brevity). this is a key point. defining hyperlinks is what good REST implementation is all about. that gives the client/user additional ways to 'discover' resources on the web.
since i defined this resource object to support both XHTML and XML media types, clients (browsers) can use the
Accepts
HTTP Header to tell the server which representation (XHTML or XML) the client wishes to recieve.
this is another key REST constraint and is easily accomplished with exyus resource classes. since XML is the
default media type for XmlFileResource
objects, i do not need to do anything in order to support XML
representations. exyus will send default XML representations for me. however, if i wish, i can override the
default transformation with one of my own. i'll leave that for another time (see figure 3).
so that's all it takes to define a resource and implement it using the exyus engine. the steps are simple and, for the most part trivial:
XmlFileResource
)this example focuses on the read-only (GET) version of the resource. in the next post on this topic, i'll show how easy it is to implement a read/write version of the product resource. without writing any C# code at all.