Scott Hanselman

Doc/Literal/Bare in XML Web Services - my thoughts on all this.

July 01, 2004 Comment on this post [7] Posted in Web Services | XML
Sponsored By

Apparently Craig Andera and Tim Ewald were recently working on an MSDN code rewrite and were talking about building doc/literal/bare Web Services vs. doc/literal/wrapped.

I'm a little confused by their respective posts, as they appear to say too different things.  (Coming up on Fox, When Smart People Disagree!) They were both in the same house, coding the same stuff, but Craig's conclusion about how to use SoapParameterStyle.Bare is very different than Tim's (and mine).

Tim suggests that getting an AddResponse type "for free" when writing code like this:

//SDH: This is bad, avoid it
[WebMethod]
[return: XmlElement("sum")]
public int Add(int x, int y) { return x + y; }

is lame, and I agree.  The generared AddResponse type is totally magic, coming (by magic) from the Method name, which is a little too tightly-coupled for my tastes.

Instead, your functions should take as parameters and return as reponses formal types that you control.  Then you can use the [SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] attribute to avoid any extra automagically-added wrapped elements.  This is purely a coding convention, it's not expressed in WSDL. 

//SDH: This is not bad, embrace it.
[WebMethod]
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
[return: XmlElement("AddResponse")]
public AddResponse Add(AddRequest req)
{
  AddResponse resp = new AddResponse();
  resp = req.x + req.y;
  return resp;
}

Tim's right on with this.  We do the same thing at Corillian with our code-generation stuff (maybe I'll present on it sometime.)  You can reuse the Request and Response messages this way, as well as take and return base classes.

However, Craig had a different view.  He simply added the bare attribute to the method call:

//SDH: This is bad, think twice
[WebMethod]
[SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare)]
public int Add(int x, int y) { return x + y; }

which results in

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <x xmlns="http://tempuri.org/">int</x>
    <y xmlns="http://tempuri.org/">int</y>
  </soap:Body>
</soap:Envelope>

Which is a non-WS-I Basic Profile compliant Web Service, as it has more than one child node under <soap:Body>.  Craig muses "To me, this just seems like nicer XML; more like how I would do it if I were just using XmlWriter and raw sockets."  I totally disagree with that statement, as XML Web Services are decidedly NOT about that level of abstraction.  If you like talking with XmlWriter and raw sockets, why not yank the <soap:envelope> and those pesky namespaces? ;) If so, there's already a spec for you

Additionally this places even more pressure on the HTTP SOAPAction header, which was always a bad idea.  Fundamentally (at least in my World View) SOAP messages should be transport neutral and that's what wsa:Action is for.

So, conclusion?  Be explicit.  Use Request and Response messages as ins and outs for your Web Services, call them out and use SoapParameterStyle.Bare to avoid the extra wrapping element.  Tim's list of reasons why is excellent.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
July 01, 2004 22:36
I know you don't usually get feedback for technical posts, so I thought I would give you a thumbs up. I really dig these posts about web services and SOAP formatting (best practices kind of stuff). It would be super cool to see you give a talk (or just a post) on best practices for web service design. I'm just getting into web services and I'm unsure of where to find good best practices. Like creating your own parameter and return types. I mean, it makes perfect sense after the fact, but I hadn't really mulled it over in my head before. Keep up the great posts, man!
July 01, 2004 22:57
I totally agree Scott. It makes much more sense (as you and Tim both agree) to explicitly define your messages/documents than to let the framework do it for you implicitly. Plus, you keep the semantic information (in this case the "Add" or "AddRequest" name) which you otherwise would only get from the SOAPAction.
July 02, 2004 1:03
I also agree with you Scott. However, I would like to spawn a slightly different topic if you don't mind. I have been wondering about collection wrappers in schema. In particular, which type definition is better? Response1 or Response2?

.complexType name="Response1".
.element name="companies" type="Companies" /.
./complexType.

.complexType name="Response2".
.element name="companies" type="Company" minOccurs="0" maxOccurs="unbounded" /.
./complexType.

.complexType name="Companies" .
.element name="company" type="Company" minOccurs="0" maxOccurs="unbounded" /.
./complexType.

.complexType name="Company".
.element name="Name" type="xs:string" /.
./complexType.

Now, if you generate .NET code from this using WSDL.exe you get slightly different results from the Response1 and Response2 classes. The notable difference is that Response2 can have empty content, that is to say that the companies property is nillable. The second thing to note is in the instance doc itself. The latter will have child elements called companies. Some people think that using a plural name for a single child element is not a good thing. However if you change it to singular then you get generated classes with an array property called company. This violates most coding conventions (even in other languages such as Java). Others might balk at the verbosity of adding a collection element wrapper for every collection. I've found that with the current set of tools it is nearly impossible to define schema such that everyone is happy (barring writing your own generators). In spite of this I would like to know if there are other reasons for choosing one way over another. Thoughts?
July 02, 2004 9:57
I prefer:

&lt;Companies&gt;
&lt;Company&gt;etc&lt;/Company&gt;
&lt;Company&gt;etc&lt;/Company&gt;
&lt;Company&gt;etc&lt;/Company&gt;
&lt;Company&gt;etc&lt;/Company&gt;
&lt; /Companies&gt;

So:

&lt;xsd:element name="Companies" type="CompanyCollection"/&gt;

&lt;xsd:complexType name="CompanyCollection"&gt;
&lt;xsd:sequence maxOccurs="unbounded"&gt;
&lt;xsd:element name="Company" type="Company"/&gt;
&lt;/xsd:sequence&gt;
&lt;/xsd:complexType&gt;

&lt;xsd:complexType name="Company"&gt;
&lt;xsd:sequence&gt;
&lt;xsd:element name="name" type="xsd:string"/&gt;
...etc...
&lt;/xsd:sequence&gt;
&lt;/xsd:complexType&gt;
July 02, 2004 12:00
It's easy: Tim is right, I'm wrong. I chose a bad example, and then did a crap job of explaining it. I may have to go back and revise that post, I dislike it so much.
July 02, 2004 16:15
Regarding, Scott's last reply: Yes, me too. But how do you give a technical reason for your preference? I can't just say pick mine because I like it. :) There are people that don't like the extra CompanyCollection (which you and I don't mind) because it adds an extra level of heirarchy in the schema and the instance doc. What are the technical advantages of using this approach? BTW, what's the difference between putting the maxOccurs="unbounded" on the sequence element instead of the Company element? And did you purposefully leave off the minOccurs="0"? I would appreciate any resources that you could point me too that give reasons why you would use one method over another for any of these points but especially the collection wrapper point.
July 02, 2004 16:54
The "technical" reason I give is:

* Each Element represents SOMETHING.
* The Response represents the Response itself (and turns into the Response Object)
* The Collection represents the Collection
* Each Company get's it's own element.

Technically, if you start listing companies AFTER the Response:

* You lose the flexibility to list OTHER STUFF along side them and refer to those things as a discreet collection (given the inflexibility of serialization today)
* The Response then becomes the CompanyCollection, and not a Response.

"Responses" should be contain "Results"...the CompanyCollection is the Result of the CompanyRequest (for example) and is contained within a CompanyResponse.


Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.