XML Files

Web Services Encoding and More

Aaron Skonnard

Code download available at:XmlFiles0305.exe(339 KB)

Q What's the difference between document/literal and rpc/encoded Web Services? What's the history behind them?

Q What's the difference between document/literal and rpc/encoded Web Services? What's the history behind them?

A There are two SOAP message styles, called document and rpc. Document style indicates that the SOAP body simply contains an XML document. The sender and receiver must agree on the format of the document ahead of time, such as traditional messaging systems like Microsoft® Message Queue (MSMQ), MQSeries, and so on. The agreement between the sender and receiver is typically negotiated through literal XML Schema definitions. Hence, this combination is referred to as document/literal.

A There are two SOAP message styles, called document and rpc. Document style indicates that the SOAP body simply contains an XML document. The sender and receiver must agree on the format of the document ahead of time, such as traditional messaging systems like Microsoft® Message Queue (MSMQ), MQSeries, and so on. The agreement between the sender and receiver is typically negotiated through literal XML Schema definitions. Hence, this combination is referred to as document/literal.

RPC (Remote Procedure Call) style, on the other hand, indicates that the SOAP body contains an XML representation of a method call such as the traditional distributed component technologies of DCOM, Corba, and others. RPC style uses the names of the method and its parameters to generate structures that represent a method's call stack (see section 7 of the SOAP 1.1 specification at https://www.w3c.org/TR/SOAP). These structures can then be serialized into the SOAP message according to a set of encoding rules. The SOAP specification defines a standard set of encoding rules for this purpose (see section 5 of the SOAP 1.1 spec) that codify how to map the most common programmatic data structures, such as structs and arrays, into an XML 1.0 format. Since RPC is traditionally used in conjunction with the SOAP encoding rules, the combination is referred to as rpc/encoded.

The document/literal approach is more straightforward and easier for toolkits to get right because it simply relies on XML Schema to describe exactly what the message looks like on the wire. SOAP, however, was created before XML Schema existed. And back then they were focused primarily on objects (hence the O in SOAP), which led to the rpc/encoded way of doing things. Since universal description languages such as XML Schema or Web Services Description Language (WSDL) weren't available back then, the rpc/encoded style had to assume that additional metadata would be available for describing the method call (such as a type library, Microsoft .NET Framework assembly, or Java class file).

Such metadata made it possible for toolkits to automatically map between existing components and SOAP messages without explicitly defining what the messages looked like ahead of time.

Looking back, rpc/encoded is mostly seen as a stop-gap measure that seemed reasonable in a world without XML Schema. Now that XML Schema is here to stay, document/literal is quickly becoming the de facto standard among developers and toolkits thanks to its simplicity and interoperability results.

The WS-I Basic Profile actually disallows the use of SOAP encoding. This is a good indication that rpc/encoded will indeed become deprecated over time. For more information on this, see "The Argument Against SOAP Encoding" on MSDN® Online.

ASP.NET WebMethods support both document/literal and rpc/encoded formats. Figure 1 provides two sample WebMethods; one uses document/literal and the other rpc/encoded. As you can see, document/literal is the default style for WebMethods. You must annotate the WebMethod with SoapRpcMethod (or the class with SoapRpcService) to use rpc/encoded instead.

Figure 1 Document/Literal vs. rpc/Encoded

[WebMethod] 
public Person MarryDocLit(Person p1, Person p2) {
    p1.spouse = p2;
    // next line will cause an exception during serialization 
    // p2.spouse = p1; 
    return p1;
}
[WebMethod][SoapRpcMethod] 
public Person MarryRpcEnc(Person p1, Person p2) {
    p1.spouse = p2;
    p2.spouse = p1;
    return p1;
}

The SOAP style is described in the generated WSDL definition so consumers know what to expect. Figure 2 shows what the WSDL binding looks like for each operation that is shown in Figure 1. Notice that the style is specified on the soap:operation element while the encoding technique is specified on the soap:body element's use attribute.

Figure 2 WSDL Binding Definition

<binding name="Service1Soap" type="s0:Service1Soap">
    <operation name="MarryDocLit">
        <soap:operation style="document" soapAction="https://example.org/MarryDocLit" />
        <input>
            <soap:body use="literal" />
        </input>
        <output>
            <soap:body use="literal" />
        </output>
    </operation>
    <operation name="MarryRpcEnc">
        <soap:operation style="rpc" soapAction="https://example.org/MarryRpcEnc" />
        <input>
            <soap:body use="encoded" namespace="https://example.org/" 
              encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
        </input>
        <output>
            <soap:body use="encoded" namespace="https://example.org/" 
              encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
        </output>
    </operation>
</binding>

Even though these WebMethods have the identical C# signatures, the SOAP messages look quite different on the wire due to the differences in style and use. Figure 3 illustrates the response from the document/literal WebMethod while Figure 4 shows the response from the rpc/encoded version.

Figure 4 RPC/Encoded Response Message

<soap:Envelope xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:soapenc="https://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:tns="https://example.org/" xmlns:types="https://example.org/encodedTypes" 
  xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body soap:encodingStyle="https://schemas.xmlsoap.org/soap/ encoding/">
        <tns:MarryRpcEncResponse>
            <MarryRpcEncResult href="#id1" />
        </tns:MarryRpcEncResponse>
        <types:Person id="id1" xsi:type="types:Person">
            <name xsi:type="xsd:string">Bob Smith</name>
            <spouse href="#id2" />
        </types:Person>
        <types:Person id="id2" xsi:type="types:Person">
            <name xsi:type="xsd:string">Mary Smith</name>
            <spouse href="#id1" />
        </types:Person>
    </soap:Body>
</soap:Envelope>

Figure 3 Document/Literal Response Message

<soap:Envelope xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <MarryDocLitResponse xmlns="https://example.org/">
            <MarryDocLitResult>
                <name>Bob Smith</name>
                <spouse>
                    <name>Mary Smith</name>
                </spouse>
            </MarryDocLitResult>
        </MarryDocLitResponse>
    </soap:Body>
</soap:Envelope>

This example also highlights one area where rpc/encoded is actually more capable than document/literal today. The SOAP encoding rules facilitate the representation of object graphs in XML such as the cyclical reference shown in Figure 4. Since there is no way to represent this with just XML Schema, the document/literal example will throw an exception if you try to return something that cannot be represented as a natural tree structure. This issue will probably be solved by defining a standard way to represent object graphs in conjunction with XML Schema. Despite this deficiency, you're still better off avoiding rpc/encoded if you really care about interoperability across today's Web Service toolkits.

Q In ASP.NET, how can I attach an image to a SOAP message using Direct Internet Message Encapsulation (DIME)?

Q In ASP.NET, how can I attach an image to a SOAP message using Direct Internet Message Encapsulation (DIME)?

A Microsoft ships an implementation of DIME in Web Services Enhancements (WSE) 1.0 for Microsoft .NET. In order to begin using the WSE in your WebMethods, you need to register a SoapExtension (called WebServicesExtension) in your web.config file, as illustrated here:

<configuration>
    <system.web>
        <webServices>
            <soapExtensionTypes>
                <add type="Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services,Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
                  priority="1" group="0"/>
            </soapExtensionTypes>
        </webServices>
    </system.web>
</configuration>

A Microsoft ships an implementation of DIME in Web Services Enhancements (WSE) 1.0 for Microsoft .NET. In order to begin using the WSE in your WebMethods, you need to register a SoapExtension (called WebServicesExtension) in your web.config file, as illustrated here:

<configuration>
    <system.web>
        <webServices>
            <soapExtensionTypes>
                <add type="Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services,Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0"/>
            </soapExtensionTypes>
        </webServices>
    </system.web>
</configuration>

Assuming you have the assembly referenced in your project, you should be able to take advantage of the Microsoft.Web.Services namespaces in your code. Attaching an image to the SOAP response is as simple as creating a DimeAttachment object and adding it to the HttpSoapContext.ResponseContext.Attachments collection. I've provided a sample DIME Web Service (called DimeServer) that exposes a single operation named GetImage. GetImage takes the name of the image file you want to retrieve from its image repository (found in the vroot's child image directory). See Figure 5 for the WebMethod code.

Figure 5 DIME Server (WebMethod) Code

using Microsoft.Web.Services;
using Microsoft.Web.Services.Dime;
[WebService(Namespace = "https://example.org/dime/")] 
public class DimeServer: WebService {
    [WebMethod] public void GetImage(string name) {
        DimeAttachment dimeAttach = new DimeAttachment("image/jpg", 
          TypeFormatEnum.MediaType, Server.MapPath(String.Format("images/{0}", 
          name)));
        HttpSoapContext.ResponseContext.Attachments.Add(dimeAttach);
    }
}

The response generated by GetImage is no longer straight SOAP; it's now a DIME message with two records. The first record is the SOAP response; the second message is the binary image. Hence, a DIME processor is needed on the client as well. Luckily, the WSE bits can be used on the client side in a similar fashion. All you have to do is change the name of the base class in your generated proxy class from SoapHttpClientProtocol to WebServicesClientProtocol. Then you can extract the binary image from the proxy's ResponseSoapContext property, as illustrated in Figure 6.

Figure 6 DIME Client Code

private void btnRetrieve_Click(...) {
    try {
        DimeServer ds = new DimeServer();
        ds.GetImage(txtFileName.Text);
        if (ds.ResponseSoapContext.Attachments.Count > 0) 
          pbResults.Image = new Bitmap(ds.ResponseSoapContext.Attachments[0].Stream);
    } catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

Figure 7 Dime Client

Figure 7** Dime Client **

Figure 7 shows the client application in action. You can download the complete sample from the link at the top of this article. For more information make sure you check out "Programming with Web Services Enhancements 1.0 for Microsoft .NET".

Q Is it possible to send and receive raw XML using a WebMethod?

Q Is it possible to send and receive raw XML using a WebMethod?

A Yes, it's possible to deal with raw XML documents—at least in the form of Document Object Model (DOM) trees—by defining your WebMethod as follows:

[WebMethod] 
public XmlNode GenericOperation(XmlNode input) { 
  // process XML input and return another DOM tree
  ••• 
}

A Yes, it's possible to deal with raw XML documents—at least in the form of Document Object Model (DOM) trees—by defining your WebMethod as follows:

[WebMethod]
public XmlNode GenericOperation(XmlNode input) { 
  // process XML input and return another DOM tree 
  ••• 
}

In this case, GenericOperation is capable of taking any XML document as input and returning an XML document as output. Using this approach basically tells the WebMethod framework that you're not interested in mapping the input/output XML documents to .NET Framework classes like you normally would. Hence, you're left processing the input document and generating the output document using traditional DOM techniques, which may or may not be what you want.

Although this approach gives you a lot of flexibility, it's important to realize what it means to clients. If you inspect the generated WSDL document for this endpoint, you'll notice that both the Request and Response elements contain wildcards (see Figure 8). This means that the client won't know anything about what you're trying to send by looking at the WSDL definition; you'll have to coordinate this information out-of-band or with a custom WSDL document. Interestingly, the same issue exists with ADO.NET DataSets. For more information on using DataSets with WebMethods, see the April 2003 installment of the The XML Files. And since this technique typically forces clients to work with the XML directly, most developers prefer to use strongly typed signatures.

Figure 8 GenericOperation XML Schema Definition

<s:element name="GenericOperation">
    <s:complexType>
        <s:sequence>
            <s:element minOccurs="0" name="input">
                <s:complexType mixed="true">
                    <s:sequence>
                        <s:any />
                        <!-- wildcard -->
                    </s:sequence>
                </s:complexType>
            </s:element>
        </s:sequence>
    </s:complexType>
</s:element>
<s:element name="GenericOperationResponse">
    <s:complexType>
        <s:sequence>
            <s:element minOccurs="0" name="GenericOperationResult">
                <s:complexType mixed="true">
                    <s:sequence>
                        <s:any />
                        <!-- wildcard -->
                    </s:sequence>
                </s:complexType>
            </s:element>
        </s:sequence>
    </s:complexType>
</s:element>

I know developers who prefer to use strongly typed signatures, but in some cases would also like access to the raw XML from within the WebMethod. The trick that makes this possible is to rewind the request message stream by setting its Position back to 0 (it's advanced during the WebMethod deserialization process). Once you've done that, you can process the stream using an XmlTextReader or by loading it into an XmlDocument, as shown in the following code snippet:

[WebMethod]
public string Add(double x, double y) {
    Stream in = HttpContext.Current.Request.InputStream; in .Position = 0;
    XmlDocument doc = new XmlDocument();
    doc.Load( in ); 
    // process raw XML input via doc 
    •••
}

At least this gives you a hybrid technique for reading the input. Dealing with the output is a little trickier because the framework doesn't expect you to write directly to the output stream. See the March 2003 House of Web Services column for more on this technique.

Q How do you load a string of XML into the contents of a specific node using the System.Xml DOM of the Microsoft .NET Framework?

Q How do you load a string of XML into the contents of a specific node using the System.Xml DOM of the Microsoft .NET Framework?

A One way to do this is to load the string of XML into a new XmlDocument object and then import the nodes into the original XmlDocument object. This is somewhat tedious, however, and it assumes that the string of XML is a complete document and not a fragment. The XmlNode class provides an easier way to solve this problem through its InnerXml property.

A One way to do this is to load the string of XML into a new XmlDocument object and then import the nodes into the original XmlDocument object. This is somewhat tedious, however, and it assumes that the string of XML is a complete document and not a fragment. The XmlNode class provides an easier way to solve this problem through its InnerXml property.

XmlNode provides InnerXml and OuterXml properties that are similar to the DHTML innerHTML and outerHTML properties. Retrieving the OuterXml property returns the XML 1.0 representation of the entire node, including the XML for the node you're on. Getting the InnerXml property, on the other hand, only returns the XML 1.0 representation of the current node's contents.

Although the OuterXml property is read-only, the InnerXml property also allows you to write XML 1.0 into a given node, overwriting its content. Doing so causes a new tree of DOM nodes to be generated and inserted on the fly. Here's an example that illustrates both properties in action:

XmlDocument doc = new XmlDocument(); 
doc.LoadXml("<person><overwrite_me/></person>"); 
XmlNode person = doc.DocumentElement; 
person.InnerXml = "<name>Marti</name><age>30</age>"; 
person.InnerXml += "<gender>female</gender>"; 
Console.WriteLine(person.OuterXml);

Running this program produces the following console output:

<person>
    <name>Marti</name>
    <age>30</age>
    <gender>female</gender>
</person>

Notice that setting InnerXml (using =) overwrites the overwrite_me element. Using the += operator, on the other hand, adds the new XML to the node's children collection without overwriting what was already there.

These properties are not part of the W3C DOM specification, but they are handy additions that can simplify moving between XML 1.0 and parts of an in-memory DOM tree.

Q In your column on the Birth of Web Services, you provide a definition of Web Services. Does the W3C agree on a definition that drives the work they're doing?

Q In your column on the Birth of Web Services, you provide a definition of Web Services. Does the W3C agree on a definition that drives the work they're doing?

A As I said in the column, the overall success of Web Services depends first and foremost on everyone agreeing on its meaning. Around the beginning of 2002, the W3C formed the Web Services Architecture Working Group, chartered to define a reference architecture for Web Services (see https://www.w3.org/2002/ws/arch). They provide the following definition in their current Working Draft:

A As I said in the column, the overall success of Web Services depends first and foremost on everyone agreeing on its meaning. Around the beginning of 2002, the W3C formed the Web Services Architecture Working Group, chartered to define a reference architecture for Web Services (see https://www.w3.org/2002/ws/arch). They provide the following definition in their current Working Draft:

A Web service is a software system identified by a URI, whose public interfaces and bindings are defined and described using XML. Its definition can be discovered by other software systems. These systems may then interact with the Web service in a manner prescribed by its definition, using XML based messages conveyed by Internet protocols https://www.w3.org/TR/2002/WD-ws-arch-20021114/#whatisws.

Interestingly, by their definition, an application doesn't require the use of SOAP or WSDL to be considered a Web Service. If you read the note that immediately follows the definition, however, you'll learn that their reference architecture does assume (in a somewhat schizophrenic way) that the higher levels of the Web Services protocol stack are indeed built on the foundation of SOAP and WSDL. In the end, the Working Group realizes that a common foundation is needed for building additional layers like security, routing, choreography, and so forth (see the GXA specs for more examples) but at the same time, they don't want to discourage experimentation and research. The most controversial area of Web Services research is that of Representational State Transfer (REST), which offers some interesting ideas on how Web Services could more fully embrace the architecture of today's Web. I suppose the Working Group's definition leaves the door open for such ideas.

I also pointed out in the October 2002 column that the Web Services Interoperability Organization (WS-I) is focused on the same problem. One of the WS-I's main goals is to "articulate and promote a common industry vision for Web services..." (see https://ws-i.org/FAQ.aspx#A02), which will ultimately help interoperability. The WS-I complements the W3C because it's more focused on practical issues like providing implementation guidelines.

The WS-I is working to produce a Web Services basic profile (see Basic Profile Version 1.0), which in my opinion serves as a more concrete and practical definition today—it essentially states that a Web Service must support XML 1.0, XML Schema, SOAP, WSDL, and Universal Description, Discovery, and Integration (UDDI) to comply with it.

Q When I try to validate an XML document for which the processor cannot find the XML Schema definition, the processor still says it's valid. Why?

Q When I try to validate an XML document for which the processor cannot find the XML Schema definition, the processor still says it's valid. Why?

A XML Schema defines two validation techniques that can be used by processors: lax and strict. Lax validation means that the processor should validate if schema information is available, while strict validation means that the processor must validate or produce an error if schema information is not available. For example, when using wildcards (xsd:any), XML Schema allows you to specify which form of validation you'd like the processor to use:

<xsd:schema xmlns:xsd="https://www.w3.org/2001/XMLSchema" 
  xmlns:tns="urn:person" targetNamespace="urn:person">
    <xsd:complexType name="OpenEndedPerson">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:any processContents="lax"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:element name="person" type="tns:OpenEndedPerson"/>
</xsd:schema>

A XML Schema defines two validation techniques that can be used by processors: lax and strict. Lax validation means that the processor should validate if schema information is available, while strict validation means that the processor must validate or produce an error if schema information is not available. For example, when using wildcards (xsd:any), XML Schema allows you to specify which form of validation you'd like the processor to use:

<xsd:schema
    xmlns:xsd="https://www.w3.org/2001/XMLSchema"
    xmlns:tns="urn:person" targetNamespace="urn:person">
    <xsd:complextType name="OpenEndedPerson">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:any processContents="lax"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:element name="person" type="tns:OpenEndedPerson"/>
</xsd:schema>

The following XML document contains a person element, which may or may not be valid, according to the previous schema:

<x:person
    xmlns:x="urn:person">
    <name>Bob</name>
    <z:skillSet
        xmlns:z="urn:skills">
        <program>WordPerfect</program>
        <program>Microsoft Office</program>
        <program>Visio</program>
    </z:skillSet>
</x:person>

When the processor validates this instance, it will first look for the appropriate schema information (like the complexType that describes the skillSet element). If it's able to locate the schema information, it will continue performing validation on skillSet's structure; otherwise it will skip the element and assume it's valid (note: in addition to strict and lax, you can also specify "skip," which tells the processor not to validate the given element).

Wildcards, however, only apply to local elements. But what about the root element? Unfortunately, XML Schema doesn't provide a way to specify or constrain what's allowed as the root element of a document. In other words, the root element of a document can be any global element in the schema. If there were such a declaration, it could allow you to specify whether to use lax or strict (like wildcards), and if you specified strict, you wouldn't run into what you're experiencing. XML Schema chose a different approach.

If the processor cannot locate schema information for the root element, it assumes that the element is of type ur-type (or anyType). Because anyType sits at the top of the XML Schema type hierarchy, everything is a valid instance of anyType. I agree that it can be misleading when the processor tells you an instance is valid when, in fact, it didn't really analyze the structure of the element. This will always be the case if the schema's targetNamespace doesn't match the namespace of the root element in the instance document (I see this bug all the time).

It's possible to catch this issue if you're willing to write a little code. If you're using MSXML 4.0, it's actually quite easy—all you have to do is explicitly call the validate function after loading the document. The validate function produces an error if it can't locate a type definition for the root element, unlike the call to load (even with validateOnParse="true"). See Figure 9 for a simple example.

Figure 9 Validation with MSXML 4.0

var dom = new ActiveXObject("MSXML2.DOMDocument.4.0");
var sc = new ActiveXObject("MSXML2.XMLSchemaCache.4.0");
// load schema into cache 
sc.add("https://example.org/person", "person.xsd");
dom.schemas = sc;
dom.async = false;
if (dom.load("person.xml"))
// did it really validate? 
{
    // calling validate makes sure it found a definition 
    // for the root element 
    var err = dom.validate();
    if (err.errorCode == 0) 
      WScript.echo("success: document conforms to DTD/Schema");
    else 
      WScript.echo("### error: " + err.reason);
} else 
    WScript.echo("### error: " + dom.parseError.reason);

If you're writing code using the .NET Framework with System.Xml, you have to do a little more. You'll need to wrap an XmlValidatingReader around the instance document, load the schema into the XmlValidatingReader's schema cache (see the Schemas property), and then explicitly move the cursor to the root element (by calling MoveToContent). Once positioned on the root element, the SchemaType property provides access to its XML Schema type definition if found. Hence, if SchemaType is null, you know it didn't locate the correct schema and, therefore, didn't perform validation. Figure 10 provides a complete example.

Figure 10 Validation with System.Xml

try {
    // prepare validating reader for instance 
    document XmlTextReader tr = new XmlTextReader("person.xml");
    XmlValidatingReader vr = new XmlValidatingReader(tr);
    // load schema into vr's schema cache 
    XmlTextReader schemaReader = new XmlTextReader("person.xsd");
    XmlSchema schema = XmlSchema.Read(schemaReader, null);
    vr.Schemas.Add(schema);
    // move vr to root element (skips whitespace/comments) 
    // and check for type definition explicitly 
    vr.MoveToContent();
    if (vr.SchemaType == null) 
      throw new Exception("Cannot locate schema definition");
    // load document with validating reader 
    XmlDocument doc = new XmlDocument();
    doc.Load(vr);
    Console.WriteLine("success: document conforms to DTD/Schema");
} catch (XmlException e) {
    // catches XML 1.0 errors 
    Console.WriteLine("### error: " + e.Message);
} catch (XmlSchemaException e) {
    // catches schema validation errors 
    Console.WriteLine("### error: " + e.Message);
} catch (Exception e) {
    // everything else 
    Console.WriteLine("### error: " + e.Message);
}

Q Should I use DateTime.Parse, Convert.ToDateTime, or XmlConvert.ToDateTime when parsing dates from an XML file?

Q Should I use DateTime.Parse, Convert.ToDateTime, or XmlConvert.ToDateTime when parsing dates from an XML file?

A It depends on the lexical format of the dates you're trying to parse. Convert.ToDateTime simply delegates to DateTime.Parse, which knows how to read date strings in different culture-specific formats that you can control:

// these are equivalent 
DateTime dt1 = Convert.ToDateTime("2/16/1992 12:15:12"); 
DateTime dt2 = DateTime.Parse("2/16/1992 12:15:12");

A It depends on the lexical format of the dates you're trying to parse. Convert.ToDateTime simply delegates to DateTime.Parse, which knows how to read date strings in different culture-specific formats that you can control:

// these are equivalent 
DateTime dt1 = Convert.ToDateTime("2/16/1992 12:15:12"); 
DateTime dt2 = DateTime.Parse("2/16/1992 12:15:12");

All of Convert's ToXxx methods that accept a string will delegate to the corresponding common language runtime (CLR) type's Parse method. In general, Parse knows how to read CLR-defined lexical representations for the given type (for example, Convert.ToDouble delegates to Double.Parse).

XmlConvert, on the other hand, was defined specifically for reading the lexical representations of XML Schema's data types:

// reads XSD lexical representation for dates 
XmlConvert.ToDateTime("1992-02-16T12:15:12")

If you're working with an XML Schema-based application, this is the one you typically want to use. For example, writing code to process XML messages automatically generated by the .NET Framework WebMethod infrastructure requires you to process XML Schema representations, which means using XmlConvert.

Send your questions and comments for Aaron to xmlfiles@microsoft.com.

Aaron Skonnardis an instructor/researcher at DevelopMentor, where he develops the XML and Web Service-related curriculum. Aaron coauthored Essential XML Quick Reference (Addison-Wesley, 2001) and Essential XML (Addison-Wesley, 2000).