Wednesday, February 20, 2008

Are You Really Using Xml Web Services?

I recently realized that it's a stretch to call the web services my company publishes as xml web services. We've always documented them as xml based, but that's a stretch. We use .Net which makes creating a web service almost brainless. We have implemented our web service as such:

[WebMethod]
public string Echo(string message) {
return "<EchoResult>" + message + "</EchoResult>";
}


This is a really simple example, but the web service accepts a string and returns a string. The string in our web services is an xml message which gets dispatched to the appropriate handler later on. So we're handling a variety of different messages and responses through a single interface using an xml string as the parameter.

What you don't realize is that this is so far from what you really want to be doing is isn't even funny. Sending a request to this method must be sent as (simply, using SOAP there would also be a SOAP wrapper):

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://foobar">string</string>


The string parameter in this case is wrapped in the string xml element. Because of this requirement the string being passed to the web service must be xml encoded to ensure the entire request is valid xml. So in our case where the string is potentially a very large xml document, the entire message must be xml encoded. The response from the web service is similar:

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://foobar">&lt;EchoResult&gt;test&lt;/EchoResult&gt;</string>

In this case the string "test" was passed to the web service. As you can see, the response is xml encoded. This again is to ensure that the xml is valid.

Because .Net makes creating these web services brainless the xml encoding is handled by .Net auto-magically. So if you are taking to the web service with a .Net client and created a web reference, the xml encoding and decoding happens behind the scenes and you won't even know it and it looks like you're passing xml messages back and forth. Now technically you are passing xml messages back and forth, but it's not pretty (IMHO). If you try to use a Java client(pick your language) the request won't work till you xml encode the xml message and you won't get your xml response unless you xml decode the response ... doesn't seem like a friendly xml interface.

A way to get around this implementation is to use XmlNode:

[WebMethod]
public XmlNode Echo(XmlNode message) {
XmlDocument dom = new XmlDocument();
dom.LoadXml("<EchoResult>" + message.InnerXml + "</EchoResult>");

return dom;
}


By specifying the parameter and return type as XmlNode, the web service accepts and returns xml. If you peak at the WSDL you'll see. So with this implementation the request does not need to be xml encoded since the web service accepts xml. The response is also not xml encoded since it returns xml. Although .Net clients will see that the parameter and return types are XmlNode, to other clients it will just look like a string. The response using the XmlNode implementation looks like:

<?xml version="1.0" encoding="utf-8"?>
<EchoResult>test</EchoResult>

This is what you'd(I'd) expect to see when calling a web service that you expect to pass and receive xml messages.

I guess one lesson to learn from this story is that if it looks too good to be true -- it probably is.

Another lesson to learn is to understand the technology you're using. I stumbled across this when I was running WireShark troubleshooting something else.

Hope this proves useful for someone else.

No comments: