Understanding Data Contracts

Data contracts, in WCF, are the preferred method of abstracting your .NET types from the schema and XML serialized types. With WCF, you have choices for creating the metadata that is used to publish your service and how that impacts the runtime serialization of your .NET types into platform-agnostic schema types that are represented in XML.

The process is all hidden, if you choose, from the developer. Primitive types are easily mapped to leverage the default DataContractSerializer. Other types are controllable through the DataContract attribute capabilities. However, if you still want control, you can always leverage XmlSerializer to manage the serialization of your types into XML. So, in the following sections, we'll first walk you through some of the ways you can work with XmlSerializer before moving on to data contracts.

All the examples so far have leveraged the default DataContractSerializer type for XML serialization/deserialization. You'll take a brief look at levering XmlSerializer for managing the XML serialization process.

XML Serialization

WCF supports two primary means of XML serialization. For a majority of scenarios, the DataContract attribute and its corresponding DataContractSerializer type are the preferred means of providing this requirement. However, the secondary method, the XmlSerializerFormat attribute, provides finer control over the XML serialization process. Additionally, by providing your own implementation of IXmlSerializable, effectively overriding .NET default serialization, you can control serialization entirely.

We will stress that you can use the data contract capabilities most of the time when developing enterprise applications. This is especially true when you control, or at least influence, both sides of the wire. Even if you don't have influence on both sides of the wire, you probably can gain enough control to emit the XML as required by leveraging data contracts.

In Listing 4-13, the solution (Example07) has been expanded to include a concrete Trade class. This class represents the object (or message) that is presented to the exchange for requesting execution on a market order.

Example. TradeService Interface with Trade Parameter
[ServiceContract(
    Namespace = "http://PracticalWcf/Exchange/TradeService",
    Name = "TradeService",
    SessionMode = SessionMode.Required)
]
public interface ITradeService
{
[OperationContract(
							IsOneWay = false,
							Name = "TradeSecurityAtMarket"
							)]
							decimal TradeSecurity( Trade trade );
}

The TradeSecurity interface is updated to take a Trade object and return a decimal result. Also recognize that the Name parameter on the operation is TradeSecurityAtMarket. We chose the name of the operation to override the default of TradeSecurity and provide a distinction of a market order vs. limit orders on the metadata.

The Trade class looks like Listing 4-14 (notice the absence of either a Serializable attribute or a DataContract attribute at the top of the class).

Example. First Few Lines of Trade Class
namespace ExchangeService
{
public class Trade
    {
        string _ticker;
        char _type;
        string _publisher;
        string _participant;
        decimal _quotedPrice;
        int _quantity;
        DateTime _tradeTime;
        decimal _executionAmount;

        /// <summary>
        /// Primary exchange security identifier
        /// </summary>
        public string Ticker
        {
            get { return _ticker; }
            set { _ticker = value; }
        }

If you launch the ASP.NET development server and view TradeService.svc in the browser, you'll see the error shown in Figure 4-8.

Error page for nonserializable or missing data contract

At this point, WCF doesn't know what to do. Therefore, let's apply the Serializable attribute to the Trade type and take a look at the generated schema, as shown in Listing 4-15.

Example. Trade Type with the Serializable Attribute
namespace ExchangeService
{
[Serializable]
    public class Trade
    {
        string _ticker;
        char _type;
        string _publisher;
...

To view the generated schema for the modified contract, first navigate to the following page: http://localhost:8888/ExchangeWeb/TradeService.svc?wsdl. Once at that page, if you locate the schema import, using the XPath /wsdl:definitions/wsdl:import, you'll see another reference to a schema. You need to load that schema as well. That location should be, depending upon your host and IP port, as follows: http://localhost:8888/ExchangeWeb/TradeService.svc?wsdl=wsdl0.

NOTE

Again, you need to first open the base WSDL and search for the <wsdl:import> element, which will provide the correct location for the imported WSDL.

Notice the addition of the wsdl0 parameter to the original WSDL request. Viewing that page, you should see something that contains XML and is similar to Listing 4-16.

Example. TradeService WSDL Definition
<xsd:import
  schemaLocation="http://localhost:8888/ExchangeWeb/TradeService.svc?xsd=xsd2"
  namespace="http://schemas.datacontract.org/2004/07/ExchangeService" />

You need to go a little deeper, opening the schemaLocation URL from Listing 4-16 to get to the type's schema. If you browse to the schemaLocation from Listing 4-16, the code in Listing 4-17 appears.

Example. Trade Schema Contract-Only Serializable (Trade.cs)
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
  targetNamespace="http://schemas.datacontract.org/2004/07/ExchangeService"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://schemas.datacontract.org/2004/07/ExchangeService"
  xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/">
  <xs:import
    schemaLocation="http://localhost:8888/ExchangeWeb/TradeService.svc?xsd=xsd1"
    namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
  <xs:complexType name="Trade">
    <xs:sequence>
<xs:element name="_executionAmount" type="xs:decimal"/>
							<xs:element name="_participant" nillable="true" type="xs:string"/>
							<xs:element name="_publisher" nillable="true" type="xs:string"/>
							<xs:element name="_quantity" type="xs:int"/>
							<xs:element name="_quotedPrice" type="xs:decimal"/>
							<xs:element name="_ticker" nillable="true" type="xs:string"/>
							<xs:element name="_tradeTime" type="xs:dateTime"/>xye
							<xs:element name="_type" type="ser:char"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="Trade" nillable="true" type="tns:Trade"/>
</xs:schema>

First, note the targetNamespace that was used. Since you didn't override the namespace using .NET XML serialization support, you get what DataContractSerializer defaults to—http://schemas.data.coontract.org/2004/07/<serviceName>. This is probably not desired. We'll get to this issue in a moment.

Second, the elements chosen by DataContractSerializer aren't the public properties but the fields (private or public) along with the underscore as part of the name; this is also an undesirable result. This is the default behavior, and fortunately you can control this by utilizing the XML serialization support that's part of the .NET Framework.

Finally, note the order of the elements—they're in alphabetical order, which is the default processing rule for DataContractSerializer.

NOTE

This code is provided in the Begin folder as part of Example07 on the Apress website (http://www.apress.com).

To control the WSDL generation, you need to switch from using DataContractSerializer to instead leveraging XmlSerializer; you can do this by decorating the service contract, at the interface level, with the XmlSerializerFormat attribute, as shown in Listing 4-18.

Example. TradeService with XmlSerializer Support (TradeService.cs)
namespace ExchangeService
{
    [ServiceContract(
        Namespace = "http://PracticalWcf/Exchange/TradeService",
        Name = "TradeService",
        SessionMode = SessionMode.Required)
    ]
[XmlSerializerFormat(
							Style = OperationFormatStyle.Document,
							Use = OperationFormatUse.Literal)]
    public interface ITradeService
    {
        [OperationContract(
          IsOneWay = false,
          Name = "TradeSecurityAtMarket"
          )]
        decimal TradeSecurity( Trade trade );
    }

Now, if you rerequest the imported namespace using the following URL, you'll see the schema updated with your targetNamespace attribute (check the schema import in the generated WSDL for the correct location):

http://localhost:8888/ExchangeWeb/TradeService.svc?xsd=xsd0

NOTE

Again, we need to emphasize that to find the nested WSDL, you must search the base WSDL for the <wsdl:import> element and then the nested import of the type schema shown in this step.

Listing 4-19 shows the new schema.

Example. New Schema with XmlSerializer Support
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
    elementFormDefault="qualified"
    targetNamespace="http://PracticalWcf/Exchange/TradeService"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://PracticalWcf/Exchange/TradeService">
  <xs:import
    schemaLocation="http://localhost:8888/ExchangeWeb/TradeService.svc?xsd=xsd1"
    namespace="http://microsoft.com/wsdl/types/"/>
  <xs:element name="TradeSecurityAtMarket">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="1" name="trade" type="tns:Trade"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="Trade">
							 <xs:sequence>
							<xs:element minOccurs="0" maxOccurs="1"
							name="Ticker" type="xs:string"/>
							<xs:element
							minOccurs="1" maxOccurs="1"
							name="Type" type="q1:char"
							xmlns:q1="http://microsoft.com/wsdl/types/"/>
							<xs:element
							minOccurs="0" maxOccurs="1"
							name="Publisher" type="xs:string"/>
							<xs:element
							minOccurs="0" maxOccurs="1"
							name="Participant" type="xs:string"/>
							<xs:element
							minOccurs="1" maxOccurs="1"
							name="QuotedPrice" type="xs:decimal"/>
							<xs:element
							minOccurs="1" maxOccurs="1"
							name="Quantity" type="xs:int"/>
							<xs:element
							minOccurs="1" maxOccurs="1"
							name="TradeTime" type="xs:dateTime"/>
							<xs:element
							minOccurs="1" maxOccurs="1"
							name="ExecutionAmount" type="xs:decimal"/>
							</xs:sequence>
							</xs:complexType>

<xs:element name="TradeSecurityAtMarketResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element
          minOccurs="1" maxOccurs="1"
          name="TradeSecurityAtMarketResult" type="xs:decimal"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

You now have a targetNamespace that reflects the namespace requirement; additionally, the elements within the Trade complexType are all the public property names and types. The XmlSerializer includes only the public properties or fields; additionally, they are serialized in the order presented in the class as requested through reflection.

NOTE

This code is provided in the accompanying code as Step1 in Example07.

It's possible to gain further control over the generated schema by continuing to leverage the capabilities of .NET XML serialization. If you want to modify or exclude public properties or fields and control the order and nullability, you can use the various attributes as described in the MSDN documentation under the topic "Attributes That Control XML Serialization." As a quick example just for fun, let's exclude the participant, modify the element name for TradeTime, and cause Ticker to be an attribute instead of an XML element. The example code now generates a schema, as shown in Listing 4-20.

To get a full understanding of the capabilities of XML serialization in .NET, please refer to MSDN and search for attributes that control XML serialization.


Example. Trade Schema Using XML Serialization Control Attributes
<xs:complexType name="Trade">
  <xs:sequence>
    <xs:element minOccurs="1" maxOccurs="1"
      name="Type" type="q1:char"
      xmlns:q1="http://microsoft.com/wsdl/types/"/>
    <xs:element minOccurs="0" maxOccurs="1"
      name="Publisher" type="xs:string"/>
    <xs:element minOccurs="1" maxOccurs="1"
      name="QuotedPrice" type="xs:decimal"/>

<xs:element minOccurs="1" maxOccurs="1"
      name="Quantity" type="xs:int"/>
    <xs:element minOccurs="1" maxOccurs="1"
name="ExecutionTime" type="xs:dateTime"/>
    <xs:element minOccurs="1" maxOccurs="1"
      name="ExecutionAmount" type="xs:decimal"/>
  </xs:sequence>
<xs:attribute name="Ticker" type="xs:string"/>
</xs:complexType>

You'll notice now that the Ticker property appears as an XML Schema attribute instead of an element, the property TradeTime is now ExecutionTime, and the element Participant no longer appears in the schema.

NOTE

The complete solution is provided in the accompanying code in the folder End as part of Example07.

So, with XmlSerialization support through the use of the XmlSerializer attribute on the service contract, it is possible to gain control over the XML Schema generation. Along with the ultimate extensibility by the implementation of the .NET interface IXmlSerializable on your .NET class, the capabilities to support just about any format required are present.

Data Contracts

Data contracts are the preferred means (because of their simplicity) for controlling what and how .NET type members are serialized to and from XML. Again, it's important to emphasize that one size does not fit all. Sometimes data contracts can't support the required schema generation. This happens most likely when you have no control over the schema and you must provide messages that match a published schema.

The first step in leveraging data contract capabilities in the WCF framework is to modify the Trade class by decorating it with the DataContract attribute, as shown in Listing 4-21.

Example. Trade Class with the DataContract Attribute
using System;
using System.Runtime.Serialization;
namespace ExchangeService
{
[DataContract(
							Namespace = "http://PracticalWcf/Exchange/Trade" )]
    public class Trade

If you rerequest the schema for the TradeService contract, you now have a Trade type that leverages DataContractFormatter support (DataContractFormatter is the default formatter type on the service contract if no Formatter attribute is present). The issue now is that you have no members of the trade that appear in the schema, as shown in Listing 4-22.

Example. Trade Class Schema with No Members
<xs:complexType name="Trade">
<xs:sequence/>
</xs:complexType>
<xs:element name="Trade" nillable="true" type="tns:Trade"/>

DataContractSerializer, by default, serializes only member fields or properties, either public or private, that are decorated with the DataMember attribute. This is in further support of the "boundaries are explicit" base tenet of SOA that the WCF team followed.

NOTE

This example is part of the accompanying code in folder Example08.

So, once you have determined which DataContract members should be present on the service contract interface, you must adorn those members with the DataMember attribute, as shown in Listing 4-23.

Example. Trade with DataMember Attributes on Fields and Properties
namespace ExchangeService
{
    [DataContract(
        Namespace = "http://PracticalWcf/Exchange/Trade" )]
    public class Trade
    {
        string _ticker;
        char _type;
        string _publisher;
        string _participant;

[DataMember( Name = "QuotedPrice", IsRequired = false, Order = 1 )]
							internal double _quotedPrice;
							[DataMember( Name = "Quantity", IsRequired = true, Order = 0 )]
							private int _quantity;
							[DataMember( Name = "TradeTime", IsRequired = false, Order = 9 )]
        Nullable<DateTime> _tradeTime;

        double _executionAmount;

[DataMember(IsRequired = true, Order = 3)]
        public string Ticker
        {
            get { return _ticker; }
            set { _ticker = value; }
        }

     [DataMember(IsRequired = true, Order = 4)]
        public char Type
        {
            get { return _type; }
            set { _type = value; }
        }

    [DataMember(IsRequired = true, Order = 10)]
        public string Publisher
        {
            get { return _publisher; }
            set { _publisher = value; }
        }

        public string Participant
        {
            get { return _participant; }
            set { _participant = value; }
        }

Pay special attention to the mix of fields and properties that have the DataMember attribute. As stated, you can apply the DataMember attribute to either fields or properties. Additionally, these fields or properties' accessibility level can be either public or private. So, regardless of the accessibility level (public, private, internal), DataContractSerializer serializes those member fields or properties. We've also applied additional properties to several of the DataMember attributes (there are only three properties—a case for simplicity). These properties control the following:

  • XML Schema optional support: IsRequired

  • Physical order in the schema: Order

  • Name of element: Name

Now, if you rerequest the schema for the DataContract type, you see the code in Listing 4-24.

Example. Trade Data Contract with DataMember Properties
<xs:complexType name="Trade">
  <xs:sequence>
    <xs:element
     name="Quantity" type="xs:int"/>

<xs:element
minOccurs="0" name="QuotedPrice" type="xs:double"/>
    <xs:element
name="Ticker" nillable="true" type="xs:string"/>
    <xs:element
name="Type" type="ser:char"/>
    <xs:element
minOccurs="0"
        name="TradeTime" nillable="true" type="xs:dateTime"/>
    <xs:element
name="Publisher" nillable="true" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
<xs:element name="Trade" nillable="true" type="tns:Trade"/>

You can see that the generated schema is produced that includes members marked with the DataMember attribute regardless of the accessibility level or whether it's a field or property. The primary reason for this method of processing data contracts is that the WCF team understands that many systems are developed by looking at predefined business classes—a code- first model. This gives designers and developers the flexibility for defining what should be included via a declarative model, without forcing developers down a significant refactoring path or back to design.

Another interesting aspect of DataMember is the Order property. The WCF framework (DataContractSerializer specifically) isn't as rigid as the XmlSeriaization framework in regard to specifying the order the elements appear. In fact, you can skip around (as shown in the example) and even duplicate Order values.

Message Contracts

Message contracts in WCF give you control over the SOAP message structure—both header and body content. You leverage the MessageContract attribute along with the MessageHeader, MessageBody, and Array variants of both (MessageHeaderArray and MessageBodyArray) to provide structure along with additional control over the content. With message contracts you can designate optional SOAP headers. With message body elements you can designate ProtectionLevel settings that provide WCF-enforced policies of signing and encrypting on those elements decorated with the ProtectionLevel property.

Message contracts work with either DataContractSerializer or XmlSerializer and provide you with additional control over the WSDL generation, specifically SOAP headers and body content. Additionally, message contracts provide support for SOAP header requirements designating specific endpoints for processing the message via the MessageHeader.Actor property. Additionally, the MessageHeader.Relay property indicates that the actor should continue to pass messages to the next endpoint after processing the request.

Message Contracts

In this section, we'll present a quick example of message contracts related to QuickReturns Ltd. Remember, three fields are required to be set to predefined values in the SOAP header. Why would you mandate headers in the SOAP request? One scenario that is common is for applying policies and rules based upon the content of the SOAP request. If you can promote or present some attribute of the request to the SOAP header, it's easily validated before any downstream code processes the request in your service implementation.

If you take a look at the Trade class in Listing 4-25 (part of the accompanying code in Example09), you can see that it has been updated with a specific namespace in addition to being decorated with the DataMember attribute with a mix of fields and properties. Additionally, the Execution class, shown in Listing 4-26, has been similarly decorated.

Example. Trade Data Contract (Partial)
namespace ExchangeService
{
[DataContract(
        Namespace = "http://PracticalWcf/Exchange/Trade" )]
    public class Trade
    {
        string _ticker;
        char _type;
        string _publisher;

        [DataMember(
            Name = "Participant", IsRequired = true, Order = 0 )]
        string _participant;

        [DataMember(
            Name = "QuotedPrice", IsRequired = false, Order = 1 )]
        internal double _quotedPrice;

        [DataMember(
            Name = "Quantity", IsRequired = true, Order = 1 )]
        private int _quantity;

        [DataMember(
            Name = "TradeTime", IsRequired = false, Order = 9 )]
        Nullable<DateTime> _tradeTime;

        double _executionAmount;

        /// <summary>
        /// Primary exchange security identifier
        /// </summary>
        [DataMember( IsRequired = true, Order = 3 )]
        public string Ticker
        {
            get { return _ticker; }
            set { _ticker = value; }
        }

Example. Execution Data Contract (Partial)
namespace ExchangeService
{
[DataContract(
							Namespace = "http://PracticalWcf/Exchange/Execution" )]
    public class Execution
    {
        [DataMember(Name= "SettleDate")]
        DateTime _settlementDate;

        [DataMember( Name = "Participant" )]
        string _participant;

        [DataMember( Name = "ExecutionAmount" )]
        double _executionAmount;

        [DataMember( Name = "TradeSubmitted" )]
        Trade _trade;

Message contracts allow the encapsulation of data contracts in addition to specifying what part of the message is in the message header and message body. So, for this example, we've added a single source code file that contains the definition of two additional classes: TradeSecurityRequest and TradeSecurityResponse. These classes are then decorated as required with the MessageContract attribute. Additionally, the members are then decorated with either the MessageHeader attribute or the MessageBody attribute, as shown in Listing 4-27.

Example. Messages—TradeSecurityRequest (Partial)
[MessageContract]
public class TradeSecurityRequest
{
    Trade _trade;
    string _particpant;
    string _publisher;
    string _ticker;

[MessageHeader(MustUnderstand=true)]
    public string Participant
    {
        get
        {
            return _particpant;
        }
        set
        {
            _particpant = value;
        }
    }

[MessageBody]
    public Trade TradeItem
    {
        get
        {
            return _trade;
        }
        set
        {
            _trade = value;
        }
    }

Looking at the MessageHeader attribute on Participant, the MustUnderstand property transfers the responsibility of enforcing this header on the SOAP request to the WCF framework. So, with a simple attribute and property value, we've now provided a simple validation. Listing 4-28 illustrates how to use the MessageContract and MessageBody attributes as applied to the TradeSecurityResponse message in this example.

Example. TradeSecurityResponse Message
[MessageContract]
public class TradeSecurityResponse
{
[MessageBody]
    public Execution ExecutionReport;
}

The response message is simply an encapsulation of the execution data contract. We've simply encapsulated the data contracts and promoted certain fields or properties as header values.

If you take a look at the update TradeService implementation shown in Listing 4-29, you'll see several changes.

Example. Updated TradeService (Partial)
[ServiceContract(
    Namespace = "http://PracticalWcf/Exchange",
    Name = "TradeService"
    )
]
public interface ITradeService
{
[OperationContract(
							Action = "http://PracticalWcf/Exchange/TradeService/TradeSecurityAtMarket"
							)]
							[FaultContract( typeof( ArgumentException ) )]
							TradeSecurityResponse TradeSecurity( TradeSecurityRequest tradeRequest );
}

The first change is the explicit specification of the Action property of OperationContract. The second is the addition of the FaultContract attribute to the TradeSecurity method. And finally, the TradeSecurity interface itself, as defined in ITradeService, has been updated to take the respective message contracts from the classes defined in Messages.cs.

Specifically, the first change, the addition of Action, is for illustrative purposes only to show how you can control these values. The WCF framework would provide default WS-Addressing and SOAP headers as required based upon the ServiceContract namespace, name, and operation name.

The second change is the FaultContract attribute. So far, all the examples have had limited exception processing. However, it's important to note that .NET exceptions and SOAP exceptions are different. Therefore, the FaultContract capability of WCF provides a way to map, encapsulate, and override how faults are handled and reported. This is important because given the cross-platform capability of WCF, it would not be feasible to enforce knowledge of .NET types. Therefore, in this example, we've wrapped the TradeService implementation in a try...catch and provided a throw of FaultException in the catch block as follows:

throw new FaultException<ArgumentException>( ex );

The final change is the modification to the TradeSecurity operation. The signature has been updated to receive and respond with the corresponding TradeSecurityRequest and TradeSecurityResponse messages, respectively.

With the service contract change, the TradeSecurity implementation changes to match the interface signature. You now have direct and simple property-level access to the SOAP headers that the client of the service contract must present. Although we are using in our examples WCF-generated proxies and .NET clients, this requirement is a SOAP standard and regardless of the implementation technology—Java, C++, or some other SOAP framework—as long as they implement the specifications, you have enforcement of your MustUnderstand rule.

In Listing 4-30, we've provided the simple value validation of the three headers presented using .NET properties from the message contract.

Example. TradeService Header Check Implementation (Partial)
public class TradeService : ITradeService
{
    const double IBM_Price = 80.50D;
    const double MSFT_Price = 30.25D;
    public TradeSecurityResponse TradeSecurity( TradeSecurityRequest trade )
    {
        try
        {
            //Embedded rules
if( trade.Participant != "ABC" )
                throw new ArgumentException( "Particpant must be "ABC"" );

if( trade.Publisher != "XYZ" )
                throw new ArgumentException( "Publisher must be "XYZ"" );

if( trade.Ticker != "MSFT" )
                throw new ArgumentException( "Ticker must be "MSFT"" );

The completed solution provides for client-side trapping of the fault exceptions leveraging the WCF capabilities. On the client side, using WCF, apply the FaultException generic with the ArgumentException type to trap and process as required by the fault condition, as shown in Listing 4-31.

Example. Client program.cs Catch Block on Fault Exception (Partial)
catch( FaultException<ArgumentException> ex )
{
     Console.WriteLine( "ArgumentException Occurred" );
     Console.WriteLine( "	Action:	" + ex.Action );
     Console.WriteLine( "	Name:	" + ex.Code.Name );
Console.WriteLine( "	Message:	" + ex.Detail.Message );
}

The FaultException type provides access to the SOAP fault headers through simple properties, allowing exception handling or reporting as needed.

The service contract side of the channel is extensible by providing your own implementation of the IErrorHandler interface. This interface, when extended, is added to your own service contract implementations, or you can add it to the DispatchBehavior.ErrorHandlers collection, which can provide overriding how messages are transformed into objects and dispatched to methods.

Summary of Service Contracts

We'll now summarize some characteristics of the service contract capabilities and the types that are available for managing the generation of the schema and the serialization process.

DataContractSerializer

This is a summary of DataContractSerializer:

XmlSerialization (XmlSerializerFormat)

This is a summary of XmlSerialization:

  • Works with the Serializable and IXmlSerializable types

  • Controlled through .NET XML serialization rules—a host of XML attributes that provide an explicit override of default behavior

  • Can control attribute vs. element—through the simple use of XML serialization attributes

  • Can control order (but the Order property is rigid in .NET XML serialization)—again, through XML serialization attributes

DataContract

This is a summary of DataContract:

  • Works with DataContractSerializer

  • Includes only DataMember in serialization

  • Overrides the Name or Namespace property—only two properties

  • Default order is reflection based

DataMember

This is a summary of DataMember:

  • Works with DataContractSerializer and DataContract

  • Overrides Name, IsRequired, and Order only—only three properties

  • Order property is not rigid

MessageContract

This is a summary of MessageContract:

  • Works with the DataContractSerializer and XmlSerializerFormat attributes

  • Provides control over SOAP message structure—header or body content

  • Leverages the MessageHeader, MessageBody, MessageHeaderArray, and MessageBodyArray attributes for customization

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset