ASMX and WSDL

Don Box's Spoutlet

Syndication

I recently spent time spelunking some corners of ASMX's support for WSDL and SOAP. I sent around my findings internally and several people mentioned that they may be of broader interest.
 
Note that everything here assumes doc/lit and where relevant, SoapParameterStyle.Bare.
 
  1. In general, you have to use the wsdl:part/@element attribute with doc/lit EXCEPT when using ASMX's “wildcard mode.”  Wildcard mode uses the wsdl:part/@type attribute and places no restriction on the type of the body element(s). In wildcard mode, ASMX won't try to deserialize into a strongly typed object but rather presents the body as one or more XmlElement references.  
    1. The "code-first" way to get ASMX to use wildcard mode is to mark an operation as SoapParameterStyle.Bare and use a single parameter (or return value) of type XmlElement or XmlElement[] that is marked as [XmlAnyElement] like this:

          [SoapDocumentMethod(ParameterStyle=SoapParamterStyle.Bare, OneWay=true)] public void DoIt([XmlAnyElement] XmlElement[] bodies) { … }

      If your parameter is an array, then multiple children of S:Body are supported. If your parameter is a single XmlElement, then only the first child element of S:Body will be used (any additional child elements are dropped on the floor at deserialization-time).
    2. The "contract-first" way to use wildcard mode is to write a wsdl:input or wsdl:output stage with exactly one message part that uses the wsdl:part/@type attribute that points to a xs:complexType that follows the following rules:
      1. The complex type can contain at most one particle in its content model and that particle must be an an element wildcard (xsd:any).
      2. There are no restrictions on the values of minOccurs/maxOccurs on the element wildcard, however, the values influence the generated code at import-time.  If maxOccurs > 1, the parameter shows up as an XmlElement[].  If maxOccurs = 1, the parameter shows up as an XmlElement.
    3. Finally, there’s a quirk in the WSDL generation when one defines a wildcard message in an ASMX service. Specifically, the complexType is marked mixed=”true” which is wrong (you cannot have mixed content under S:Body).
    4. There is a way to programmatically define an ASMX service or proxy to collect all headers by defining a field of type SoapUnknownHeader[] and marking your methods with the [SoapHeader] attribute that names the field. 
    5. Wildcard mode relies on WSDL constructs that aren't WS-I BP 1.0 compliant. However, if you restrict yourself to single-element bodies (e.g., just use XmlElement, not XmlElement[]), your messages can still be BP compliant even if your descriptions aren't.

  1. When not in wildcard mode (that is, when you're using the wsdl:part/@element), ASMX will try to deserialize each child element of S:Header and S:Body into a field (for headers) or parameter/return value (for bodies).
    1. ASMX ignores the order of message parts at deserialization time. Specifically, body parts A and B can appear in either order on incoming messages.
    2. Use of soapbind:header or soapbind:body implies that parts are OPTIONAL, not mandatory. Null references are translated into missing elements and vice-versa.
    3. ASMX doesn't handle child elements of S:Header or S:Body with duplicate QNames well.
      1. ASMX cannot import a WSDL binding that has two or more soapbind:body elements (or two or more soapbind:header elements) that reference the same global element declaration. ASMX can cope with a WSDL binding that specifies the same QName for exactly one soapbind:header and soapbind:body element however. Moreover, ASMX cannot define a method that results in such a binding. If you have two parameters (or two [SoapHeader] fields) that would result in the same QName, ASMX will produce an error.
      2. If at deserialization-time more than one child of S:Header or S:Body matches a given field/parameter, ASMX will deserialize the first element in the message that matches. Additional matching header elements will go into the SoapUnknownHeader array if present. Additional matching body blocks are silently dropped on the floor.
 
The net-net of this is that pragmatically ASMX treats the soapbind:header/soapbind:body like an XSD all compositor that uses minOccurs=0 on each particle and has an extra xsd:any interleaved between each particle (which technically can't be expressed in XSD or even RNG).
 
For example, the following WSDL:
 
<wsdl:input>
  <soap:body parts=”A B C” use=”literal” />
  <soap:header message=”tns:MP” part=”D” use=”literal” />
  <soap:header message=”tns:MP” part=”E” use=”literal” />
  <soap:header message=”tns:MP” part=”F” use=”literal” />
</wsdl:input>
 
Is equivalent to the following XSD (modulo the lack of interleaved wildcards):
 
<xs:element name=”Envelope”>
  <xs:complexType>
    <xs:sequence>
      <xs:element name=”Header” minOccurs=”0”>
        <xs:complexType>
          <xs:all>
            <xs:element ref=”tns:D” minOccurs=”0” />
            <xs:element ref=”tns:E” minOccurs=”0” />
            <xs:element ref=”tns:F” minOccurs=”0” />
          </xs:all>
        </xs:complexType>
      </xs:element>
      <xs:element name=”Body” >
        <xs:complexType>
          <xs:all>
            <xs:element ref=”tns:A” minOccurs=”0” />
            <xs:element ref=”tns:B” minOccurs=”0” />
            <xs:element ref=”tns:C” minOccurs=”0” />
          </xs:all>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>
 

Posted Nov 21 2004, 09:32 PM by don-box

Comments

SOAphisticated wrote Getting raw XML messages from ASMX
on 11-22-2004 8:17 AM
Service Station wrote Don documents the limits of ASMX-
on 11-23-2004 2:51 AM
Christophe Pichaud wrote re: ASMX and WSDL
on 11-25-2004 7:40 AM
Hi Don,
I would not to be non-pleasant but you can't design something witch lokk like like auto-descriptive and just use XML.
As you known in the MAPI and in the OLAP sub-systems (let's call it with that word to think of it as a philosophy), the had to think about thoses kinds of problems and abstraction slayers but, as i want to to dig, as you want to dive, with something which is very descriptive.
On the database model, it's called metadata but when you realize and use it in the MAPI API world, what does it looks like.
Its just an getHierarchy(à like-call and then you alwyas call a getProperty() and then you map your ID into something which is extensible.

There is no XMl or DTD or bulshit... It's simple. It's clear. It's juts a define in a xxx.h deplyed into the platforme SDK.

I don't wand to say XML is not a big and wonderfull step for the industry but, (I Hope my poor english will not make my sentence foolish), in the XML industry ther are too much think to just say, ok guys here is my struct.

I call it a struct, because its only a definition file at all.

I won't to be too much a patriot, but french hav invented the language of the internet and thoses derivated technologies. (you remember ?)

Ok, let's get out of thoses nasty ownership questions...

Look it another way.
Do you think a guy like me will appreciate to have some much technologies invoolved in, to provide just a single do it method for all this great soft.

Do you want to reinvetnt the InvokeHelper method from IDispath ?

Ok, but XL do not have the absract layers on which we can build a OLE2 next tehcnology for everybody, and for the great actor in the industry, the software makers.

I can't tell any of my clients, XML derivated techn,logy is your best way of doing business.
No, don.
Not that way.

Ok, I go the swimming pool. My triathlon facet need training.
Have fun.
Christophe.
Matt Powell wrote More Random Good Stuff from Don
on 11-29-2004 12:42 PM
Christophe Pichaud wrote re: ASMX and WSDL
on 11-30-2004 5:43 AM
OK, I try a look at this url: http://blogs.msdn.com/mpowell/

--
I go to a msdn seminar in Paris in few minutes, there will be Eric Rudder and I think he'll taslk about VS2005 and MS stuff.
I hope it will be good.
--

Just a question ?
When do you think we could supress the XMl technology ?
I think I could be a question not so stupid.

In the past, we had ole applications, now we have several thousands com coponents and now legacy systems can interop via thoses XML files. Gret ! but what a pain ... it's a shame, all those xml technologies, well-don redifined every 3 months, ppppppfffffffffff.

I loved my Win32 API.
I think the XML API will not have so many fans and the fans from today, will grew up to have responsabillities because if they continue to play in the development battelfield, it's horrible.

Some friends uses DOM, JDOM, Xerces, MSXML, SOAP, truc-truc, zob-zob and pouette-pouette.... oh no. It's confusion. It's too fast, too much.

So my question is.
How many year the XML guys will realize that the XML ages are not the real big stuff (as BillG wanted with OLE2).

Indigo ?
I hope.
It's difficult to have betas or DVD but, I hope in a couple of months to study it in the deep way.

But, when they have covered the facts, in MSDN events, its' presented like just a BizTalk transport....

What ? just a transport ?
The gret DCOm-.NEt-.remoting - all in one just a sub-component for BizTalk. I hope not.

DCOM for love.
RPC for ever.
No more Java for me.
Christophe.
http://www.cpixxi.com
Deep Thoughts... wrote Don's Take on ASMX and WSDL
on 12-01-2004 7:31 PM
Kirk Marple wrote re: ASMX and WSDL
on 12-23-2004 10:23 AM
Don,

your post reminded me of an issue i've been having with SOAP serialization.

you might be the only one in the universe to know the answer to this... :)

i have a C# class which has a string property, and i'm serializing this class into a SOAP body.

the string property actually contains another object serialized to XML, and i'm finding that this property in the SOAP body is getting HTML-encoded.

i.e. <Array><Item /></Array> is becoming &ltArray&gt etc.

is there a way to pass the stringified XML thru un-encoded? should i be using an XmlNode or XmlDocument property to serialize the XML data into the SOAP body un-encoded?

is there a best practice for doing this? i just want to serialize some opaque XML data along with the C# class.

Thanks!
Kirk
Don Box wrote re: ASMX and WSDL
on 12-23-2004 10:27 AM
Kirk,

If you're using version 1.1, the answer is to use a field of type XmlElement or XmlNode.

If you're using version 2.0, you can use that technique or write a simple class that implements IXmlSerializable and then reads/writes whatever you want.

IXmlSerializable exists in 1.1 but is not supported until 2.0.

DB
Kirk Marple wrote re: ASMX and WSDL
on 12-23-2004 10:44 AM
Thanks for the ideas...I'm doing this with .NET 2.0, actually.

That string property came from using an XmlSerializer to serialize an object to a StringWriter. I can't see a way to use XmlSerializer to write to something which would directly produce an XmlElement.

I guess i could use XmlDocument.Load to load that serialized string into a document and grab the DocumentElement from there. Maybe there's a more direct way?

Thanks for the quick response,
Kirk

Add a Comment

(required)  
(optional)
(required)  
Remember Me?