Update: Be sure you read Tim Ewald's post about Doc/Literal/Bare - as I explain elsewhere, this post tells only half the story, and in fact mostly misses the point.
My, my, it has been quiet around here for the last week, hasn't it? My excuse is that I was in New Hampshire all week, working heads down on the MSDN rewrite with Tim Ewald and some other friends. My other excuse (always have a backup ready) is that I'm working on some big changes to this blog...but more about that soon enough.
Tim is always a font of entertaining but useless jokes, and enlightening and useful XML knowledge. One thing he pointed out to me this week was SoapDocumentMethodAttribute, in particular when specified with SoapParameterStyle.Bare.
Allow me to explain. Compare the XML produced by the following two functionally equivalent SOAP endpoints:
[WebMethod]
public int Add(int x, int y) { return x + y; }
and
[WebMethod]
[SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare)]
public int Add(int x, int y) { return x + y; }
Here are the request/response messages for the first variation:
POST /play/bare.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Add"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
and here they are for the second variation:
POST /play/bare.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Add"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
To me, this just seems like nicer XML; more like how I would do it if I were just using XmlWriter and raw sockets.
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
Notice the big difference? With the second variation, the wrapper element that corresponds to the method name has been removed. Which is nice, because it's superfluous - the method is already specified by the SOAPAction header. This is particularly nice in the response message where that extra level of indirection looks a little silly.
The problem is, however, is that SOAPAction is an HTTP header which ties you to HTTP as a protocol unless you have endpoints with only one method - in other words the context of the body either has to be defined using an HTTP construct or be implicit from the endpoint itself
ReplyDeleteFirst, I'm not sure I even agree with that whole "Oh, maybe we want to switch to protocol X" line of argument...it smacks of the "we might want to switch from SQL Server to Oracle some day" line of thought that leads to horrendous architectural abominations. Second, is not this problem solved by WS-Addressing? Third, RESTians would argue that having the operation implicit from the endpoint is a fundamental goodness, although clearly the ASP.NET bits don't work that way today. Of course, the ASP.NET bits are currently tied tightly to HTTP. ;)
ReplyDeleteBut in any event, what I've posted is only a small part of the story. I'm hoping Tim will get his ass in gear and post the rest of what he has to say before too long; I don't want to scoop him. I just found this particular attribute interesting, as I didn't know about it before.
hmmm - how adversarial ;-)
ReplyDeleteIt wasn't so much a switch protocols kind thing as a "I might not want to use HTTP in the first place" kind of thing. And I know we are talking about an ASP.NET attribute - but then it wasn't so much about the attribute, rather the resulting message schema.
I agree that possibly 1 endpoint = 1 operation is a good thing, but I was just pointing out that adopting that schema either bound you to HTTP or forced you to 1 endpoint = 1 operation.
I'll await Tim's post with interest :-)
Noticed how the namespace is repeated then with each parameter? This seems ugly to me, and would rather have the wrapper element and the namespace declared once. Also if the the number of parameters if larger (which is bad design, but point still worth mentioning) then the namespace repeating will make the whole packet larger.
ReplyDeleteRichard, you ignorant slut!
ReplyDeleteJust kidding. :) Yes, I too wish Tim would hurry up and post. We'll see - I was bugging him about it all last week. If he drags his feet any more, I'm going to start writing his posts for him.
Cleve: you're right, that is ugly, but generally not a problem since the "other things you do" that I waved my hands at take care of it. Suffice it to say that the Calculator example I chose sucks. Keep your eyes peeled for what Tim has to say on this one.
On the packet size front, compressing your HTTP stream is a great idea to begin with, and should take care of any issues with repeated namespaces to boot.
To compare moving SOAP messages over something other than HTTP to switching from SQL Server to Oracle is a bit disingenuous. The whole point of serializing a request into a SOAP document should be that it's transport neutral. That's hardly the same thing as assuming that your TSQL implementation will port to Oracle.
ReplyDeleteMy biggest problem with the "bare" example is that you are losing some semantic information from your soap document (that the Add method is what you are calling). Plus, since "AddResponse" is what still comes back as a reply, it no longer matches the request.