XML Serialization and Web Services





XML Serialization and Web Services

As mentioned earlier, .NET Web services use the XmlSerializer as the engine for sending and receiving SOAP messages. Therefore, when creating Web services and Web service clients, knowledge of how the XmlSerializer works is very helpful. Understanding how Web services use the serializer is even better.

To begin with, although you can't actually work with the XmlSerializer objects that will be created to send and receive the SOAP messages, the classes you create will be used with the serializer. So, in the end, the attri butes you use with the class will affect the schema of XML.

By default, .NET Web services are literal schema-based XML. They are not encoded XML. Thus, the attributes to use from System.Xml. Serialization are the ones that start with Xml and are for literal XML. Listing 5.8 shows a Web service that uses XML Serialization to control the XML output from the service.

A Web Service with XML Serialization Attributes
<@% WebService Language="C#" Class="Service1" %>

using System;
using System.Web.Services;
using System.Xml.Serialization;

public class Service1 : WebService
{
     [WebMethod]
     public string SubmitCustomer(Customer sustomer)
     {
         //some implementation here
         return "some string";
     }
}

     public class Address
     {
          [XmlArray("StreetName")]
          [XmlArrayItem("Name")]
          public String[] Street;

          public String City;
          public String State;
          [XmlAttribute]
          public String ZipCode;
     }

     [XmlRoot("Customer", Namespace="http://customer")]
     public class Customer
     {
          [XmlAttribute]
          public String Name;

          [XmlElement(Namespace="http://address")]
          public Address[] Address;
     }

If you may want to use encoded XML with your Web service, then you can override the default of using literal XML, and instead specify that encoded XML should be used. This is done with the Use property on the [SoapDocumentMethod] attribute. If you set this property to SoapBindingUse.Encoded, then the Soap attribute is used, and the resulting XML within the SOAP body is encoded. Listing 5.9 shows how the SoapBindingUse enum can be applied to a Web service.

Setting the Use Property of a Web Service to Encoded
<@% WebService Language="C#" Class="Service1" %>

using System;
using System.Web.Services;
using System.Xml.Serialization;
using System.Web.Services.Protocols;

public class Service1 : WebService
{
          [WebMethod]
          [SoapDocumentMethod(Use=SoapBindingUse.Encoded)]
          public string SubmitCustomer(Customer sustomer)
          {
               //some implementation here
               return "some string";
          }
}

     public class Address
     {
          public String[] Street;
          public String City;
          public String State;

          public String ZipCode;
     }

     public class Customer
     {
          public String Name;

          [SoapElement(Namespace="http://address")]
          public Address[] Address;
     }

Because encoded XML is used most often with RPCs (remote procedure calls) as defined in Section 7 of the SOAP specification, you can state that your Web method is an RPC SOAP operation (as defined in Section 7) by using the [SoapRpcMethod] attribute. By default, this attribute uses encoded XML. As a matter of fact, you can't set the Use property to literal with this attribute, because RPC operations with literal XML aren't supported in .NET version 1. Listing 5.10 shows an rpc/encoded Web service that uses the XML Serialization attributes for encoded SOAP.

Using the Encoded SOAP Attributes
<@% WebService Language="C#" Class="Service1" %>

using System;
using System.Web.Services;
using System.Xml.Serialization;
using System.Web.Services.Protocols;

public class Service1 : System.Web.Services.WebService
     {
          [WebMethod]
          [SoapRpcMethod]
          public string SubmitCustomer(Customer sustomer)
          {
               //some implementation here
               return "some string";
          }
     }
     public class Address
     {
          public String[] Street;
          public String City;
          public String State;

          public String ZipCode;
     }

     public class Customer
     {
          public String Name;

          [SoapElement(Namespace="http://address")]
          public Address[] Address;
     }

The Web service infrastructure can create multiple XmlSerializer objects if you want to use a class for both encoded XML and literal XML. This will happen automatically if you use the same class with two different methods, of which one is literal and the other is encoded.

When doing literal XML, you also can take advantage of the [XmlAnyElement] and [XmlAnyAttribute] attributes to grab untyped XML for which the schema is unknown to you. This is particularly advantageous for Web services, owing to .NET Web services' loose coupling.

By default, .NET will ignore and throw away any XML that you don't explicitly expect. This can be an asset, because it allows clients and servers to interact with future versions of the service that may send extra, but not required, XML.

For example, if you send this XML:

<?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>
    <EchoString xmlns="http://tempuri.org/">
      <str>string</str>
      <extraInfo>this is extra stuff</extraInfo>
    </EchoString>
  </soap:Body>
</soap:Envelope>

To this service:

[WebMethod] 
public String EchoString( String str )
{
     return str;
}

Then you will notice that the <extraInfo> element is lost. There is no parameter into which to serialize this XML. If you can't anticipate at design time what all of the XML will look like, then you can use the [XmlAnyElement] and [XmlAnyAttribute] attributes instead. Usually, you can put these on an XmlNode[] and then look through this array. The following method shows how you can add this extra parameter:

[WebMethod] 
public String EchoString(
           String str,
           [XmlAnyElement] XmlElement[] extraInfo )
{
     return str;
}

Now, this newly modified code will allow the developer to see the <extraInfo> element with its resulting data. The method code could hand this off for further processing or to enforce a specific version by returning a SOAP fault (that is, by throwing a SoapException).


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows