exyus workflow example
i was giving a talk this week on the patterns i use in the Exyus HTTP engine and the topic of 'workflow' came up. "These HTTP-based classes are nice, but what if you need to do some workflow in there?" is the way the question usual goes. it's all there - all cool, but i had no example.
until now [grin].
as part of my project to shadow scottgu's ASP.NET MVC demo using my own Exyus engine, i worked up a small example that validates the existing of a 'foreign key' field in a PUT entity body. works like this:
i need to PUT a product record that contains a *valid* (existing) category reference. if the category record does not exist, kill the PUT. keep in mind i am currently implementing this products/categories example using my XmlFileHandler
that uses files for storage. ok, the product XML looks like this:
<product> <id>123</id> <name>shoe</name> <quantity>10</quantity> <category>junk</category> </product>
and here's the Exyus class that contains the resource definition (see my previous post on how i did this) along with some custom code in the Put()
method to validate the category:
public override void Put() { // make sure the category exists! XmlDocument xmldoc = new System.Xml.XmlDocument(); XmlNode node = null; string cid = string.Empty; // get category from the incoming body xmldoc.Load(this.Context.Request.InputStream); node = xmldoc.SelectSingleNode("//category"); cid = (node != null ? node.InnerXml : string.Empty); try { // make sure the category already exists! Requestor req = new Requestor(); ExyusPrincipal ep = (ExyusPrincipal)this.Context.User; req.Credentials = new NetworkCredential(((ExyusIdentity)ep.Identity).Name, ((ExyusIdentity)ep.Identity).Password); string url = string.Format("{0}://{1}{2}{3}", this.Context.Request.Url.Scheme, this.Context.Request.Url.DnsSafeHost, "/xcs/data/products/categories/", cid); req.Execute(url,"head"); } catch (HttpException hex) { // not found! if (hex.GetHttpCode() == 404) throw new HttpException(404, "category [" + cid + "] not found"); else throw new HttpException(hex.GetHttpCode(), hex.Message); } // go ahead and do the rest of the work base.Put(); }
note that i simply make a HEAD
request back to the server using the supplied category value in the URL. if it doesn't exist, i get a 404 back and can then format an informative response for the caller.
here's the whole HTTP exchange:
REQUEST: ************** PUT /xcs/data/products/shoe HTTP/1.1 if-match: "ihkMhXfJIqQJOQcgubHk9g" Host: localhost Accept: */* Content-Length:96 <product> <id>123</id> <name>shoe</name> <quantity>10</quantity> <category>junk</category> </product> RESPONSE: ************** HTTP/1.1 404 Not Found Server: Microsoft-IIS/5.1 Date: Thu, 15 Nov 2007 04:31:31 GMT X-Powered-By: ASP.NET Connection: close X-AspNet-Version: 2.0.50727 Cache-Control: private Content-Type: text/html <html> <head><title>404 Error</title></head> <body><h1>404 Error</h1><p>category [junk] not found</p></body> </html>
and there's lots of other things that can be done as well. so handling workflow within the Exyus resource classes is a piece of cake, really.