POX / XMLHTTP in .NET 2.0
Note: This code has now been migrated to a codeplex project. For the latest source and dos go to www.codeplex.com/poxnet.
Recently I was working on an internal project that required me to invoke a set of POX (Plain Old XML) services from a windows client application. For those that don’t know what POX is, it’s basically a web page that receives and returns XML content. How does this differ from an ASMX? Web services transfer SOAP messages, while POX services carry any kind of XML you can think of. SOAP uses well defined contracts for passing data back and forth. Also SOAP supports advanced protocols such as WS-*. POX services on the other hand are kind of the outlaws of the services world in that there are very few constraints imposed. That does not mean that constraints cannot be enforced, for example by creating an XSD, but it means that the message format itself is completely open.
Here’s an example of a simple POX request message for illustrative purposes.
<?xml version="1.0" encoding="utf-8" ?>
<order orderNumber="12345" account="acme" accountNo="999" >
<item productNumber="12345678" qty="5" price="29.99"/>
<item productNumber="87654321" qty="10" price="35.99"/>
The response from the POX service might look like this.
<?xml version="1.0" encoding="utf-8" ?>
<orderResponse orderNumber="12345" account="acme" accountNo="999" >
In the early days when XML first appeared on the scene, POX services were quite common. Often POX was (and is still used) for doing AJAX style application development. Additionally it is not uncommon for POX style services to be used on the corporate intranet (as in my example). Now for making POX calls Microsoft provides the XMLHTTP object along with the MSXML parser. The XMLHTTP object provides the ability to post an XML string off to a URL and to receive a response either synchronously or asynchronously. As IE supports instantiating COM objects, this makes XMLHTTP the perfect answer for invoking POX from both windows and web clients.
Now flash forward to .NET. So what kind of support do we have natively in .NET for doing POX? It turns out very little. Basically you can do it, but you have to manage the streams and the transport yourself. POX is supported in WCF, but my application was not using .NET 3.0 and I really wanted to find a way to support it in 2.0. Another option was to use XMLHTTP via interop, but that seemed less than optimal.
So after several hours of trial and error, here’s how you do it in .NET.
Post to the request:
1. Create a stream that contains the xml that you want to post. (If you are starting from an XmlDocument then you need to write the document to a stream using an XmlWriter)
2. Create a byte array and read your stream into the byte array
3. Create a web request.
4. Write the byte array to the request stream
Get the response
1. Grab the response stream from the web request
2. Create a byte array for storing the resulting stream
3. Read the response stream into the byte array buffer. The data is delivered over the stream in chunks so you need to continually read until the buffer is emptied.
4. Read the buffer back into a stream (To convert this back to a document then you can pass the stream to an XmlDocument constructor.
Here’s the code….
public XmlDocument Post(string url, XmlDocument document)
//convert the document to stream
MemoryStream Stream = new MemoryStream();
XmlWriter Writer = XmlWriter.Create(Stream);
//reset the stream position
Stream.Position = 0;
//create the request and set the content type and length
WebRequest Request = WebRequest.Create(url);
Request.Method = "POST";
Request.ContentType = "text/xml";
Request.ContentLength = Stream.Length;
//get the request stream and post the xml
Stream RequestStream = Request.GetRequestStream();
RequestStream.Write(Stream.GetBuffer(), 0, (int) Stream.Length);
private XmlDocument GetResponseXml(WebRequest request)
//grab the respons stream
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ResponseStream = response.GetResponseStream();
//create the response buffer
byte ResponseBuffer = new byte[response.ContentLength];
int BytesLeft = ResponseBuffer.Length;
int TotalBytesRead = 0;
bool EOF = false;
//loop while not EOF
//get the next chunk and calc the remaining bytes
int BytesRead = ResponseStream.Read(ResponseBuffer, TotalBytesRead, BytesLeft);
TotalBytesRead += BytesRead;
BytesLeft -= BytesRead;
//has EOF been reached
EOF = (BytesLeft == 0);
//create a memory stream and pass in the respones buffer
ResponseStream = new MemoryStream(ResponseBuffer);
//load the stream into an xml document
XmlDocument ResponseDocument = new XmlDocument();
I was elated once I saw the code actually working. However a few things kept nagging at me about my implementation.
For one thing it was the fact that I was passing an XmlDocument to the Post method. I vowed years ago when I first laid eyes on the classes of the XmlSerialization namespace, that I would never write ‘ConvertMyObjectToXml’ and ‘ConvertXmlToObject’ methods again unless it was an absolute necessity. Although I could make my objects serializable and then manually serialize them to an XmlDocument , and deserialize the response, I felt like I shouldn’t need to. What I really wanted was a Post(object objectToPost) method that would handle all the XML serialization and transport for me. In the same way I wanted to have a GetResponseObject() method that returns to me a deserialized object based on the XML stream it received.
Second, I felt that the methods above were handling too much. I might want to change certain properties on the WebRequest object such as which credentials to use. Or I might need to use a CookieContainer for passing cookies in the post. In my implementation, the underlying request is locally scoped and shielded from the caller. I could have expanded the signature of the methods to accept additional parameters such as the request itself, but this then would require for me to always explicitly manage creating and destroying request instances, which I was trying to avoid.
Lastly the other problem was that the methods were too tightly coupled. I might want in one instance to send an XmlDocument and return an object, or vice versa. In another scenario, I might want to just pass a stream directly and then return a document or an object.
Bearing all of this in mind I decided what I really wanted was a helper class that would handle instantiating a WebRequest object and configuring it with default values, while still allowing access to the underlying request for further configuration. Also I wanted the helper class to contain various Post and GetRequest methods allowing posting and retrieving in different formats including an XML serializable object. And so I wrote the POXClient class.
Here’s the highlights of the functionality the class provides (I added a few extras)
1. Encapsulates a WebRequest. This underlying request is managed by the helper object, but you can access it directly via a WebRequest.Request property.
2. Provides overloaded Post methods for passing an XmlDocument, Stream, or an XML serializable object.
3. Provides several methods for retrieving the response as either an XmlDocument, an object or a Stream. Although you can get to the response stream directly off of the response object, this method returns a MemoryStream created off of the original response Stream. The advantage of this is that you can reread the MemoryStream several times whereas the actual response stream is forward only allowing it to be read once.
4. Provides tracing of the xml payloads sent and received
5. Allows configuring the underlying xml reading and writing.
Here’s an example of how you use the new class…
public OrderResponse SubmitOrder(Order order)
POXClient Client = new POXClient("http://Orders/SubmitOrder.aspx");
Now let’s say you want to submit an object, but you want to receive an XmlDocument rather than a reconstituted object. No problem, you can use the following syntax.
Also you can still access the underlying request and response if you need them. So let’s say you need to examine the cookies that were returned as part of the response.
HttpWebResponse Response = (HttpWebResponse) Client.Request.GetResponse();
Cookie SomeCookie = Response.Cookies["SomeCookie"];
Or you want to configure the request to use default credentials.
Client.Request.Credentials = CredentialCache.DefaultCredentials;
Finally you can also override the default XmlWriter and XmlReader settings through setting the ReaderSettings and WriterSettings properties, i.e.
XmlWriterSettings Settings = new XmlWriterSettings();
Settings.Indent = false;
Settings.OmitXmlDeclaration = true;
Settings.CheckCharacters = false;
WriterSettings = Settings;
POXPage / POXCommon
I thought my work was done having completed POXClient. However, as I was throwing together a sample application to show how to use the new POXClient class, I realized I needed to have some kind of POX server. Often a POX Server is simply a web page that receives an XML Post and returns XML content. As I started to write a sample page, I realized that the dilemmas were the same on the server as on the client, i.e. you need to maange the streams, serialization and deserialization in the same manner. So, I fired up my IDE along with Resharper and began refactoring out my POXClient into a separate POXCommon class. POXCommon contains the basic logic for serialization / deserialization as well reading and writing from a stream into a memory stream. The nice thing is that POXCommon knows nothing about the source of the stream, so it is completely decoupled from the source and destination thus allowing it to be reused in many scenarios. POXClient now just grabs the underlying streams from the request / response object and passes them to the appropriate methods on POXCommon.
Thus having POXCommon in place, I was now able to tackle a new POXPage class. Simply put, POXPage is a base page class that exposes a set of GetRequest and WriteResponse methods that will either accept or return objects, streams or documents. Just to show you how easy it is to write a page that will accept a POX message. Check out the code below for the SubmitOrder.aspx page that is included in the sample.
protected void Page_Load(object sender, EventArgs e)
Order CurrentOrder = GetRequest<Order>();
if (CurrentOrder != null)
OrderResponse OrderResponse = new OrderResponse(CurrentOrder, "confirmed", "1000");
The base page sets the content type and such for you. GetRequest automatically intercepts the request stream, reads in the XML and deserializes to the requested object type. WriteResponse does the reverse with the response object.
What’s in the BOX?
If you check out the attachment you’ll find a solution that has 4 projects. The solution is built around the order scenario I described the beginning of this post. Just to reiterate, this is just for illustration. The schema I have used is very simplistic, the service is unsecure, and the code is mostly demo code. But it does illustrate all the different parts and how they function.
Here’s a summary of each of the projects.
POXUtils – Contains POXCommon, POXClient and POXPage classes.
POXData – Contains Order, OrderResponse serializable classes.
POXWeb – Contains a web project with a simple SubmitOrder.aspx page that inherits from POXPage. The port is hard wired to be 4000 for the website because I didn’t want to require people to have IIS running. Also the logic within the page is totally ridiculous as all it does is take the request and repackage it into an approved order (if only life were so simple).
POXClient – Contains a console app that creates an order, instantiates a POXClient and submits the order. The received OrderResponse is then outputted to the console window so that you can see that data is roundtripping.
After spending much too much time on this library that evolved out of a simple internal tool I was building that relied on POX, what are my thoughts on how usable this library will be? Well, I think it will be incredibly useful to some, and totally useless to many :). But even if it helps one than I really believe it’s worth it!
Also if you have any ideas on how to improve the code please let me know. You'll find almost no exception handling within as all the code is delegating to objects that inherently provide handling. For example if you pass an unserializable object then the serializer will throw a nice meaningful exception for you.
Have fun and happy POXing.