Share via


Message Contracts

Retired Content

The Web Service Software Factory is now maintained by the community and can be found on the Service Factory site.

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.
This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Retired: November 2011

The MessageContract attribute in WCF is used to support the schema generation of SOAP messages. Typically, you will use a message contract if you want to define a message that includes custom SOAP headers or where you want to compose a message from multiple data contract types.

When a SOAP schema is generated by the data contract serializer, you must follow specific rules. For example, the SOAP body element in WS-I Basic Profile—compliant services can only contain one child element. In many cases, you may need to control that schema instead of using the default behavior of the data contract serializer, which is where the MessageContract attribute comes into play.

The MessageContract attribute is used on a class that defines the data types or contracts that will be added to a message header or body. The following code example shows a data contract class named SearchCriteria that is included in a message contract class named FindEmployeeRequest.

[System.Runtime.Serialization.DataContractAttribute()]
public partial class SearchCriteria 
{
    private int EmployeeIDField;
    private string FirstNameField;
    private string LastNameField;

    [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
    public int EmployeeID
    {
        get { return this.EmployeeIDField; }
        set { this.EmployeeIDField = value; }
    }

    [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
    public string FirstName
    {
        get { return this.FirstNameField; }
        set { this.FirstNameField = value; }
    }

    [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
    public string LastName
    {
        get { return this.LastNameField; }
        set { this.LastNameField = value; }
    }
}

[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
public partial class FindEmployeeRequest
{
    [System.ServiceModel.MessageHeader()]
    public string Priority;

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace =
                     "http://EmployeeService/EmployeeService/2006/06", Order = 0)]
    public SearchRequest SearchRequest;

     public FindEmployeeRequest()
    {
    }
    public FindEmployeeRequest(SearchRequest SearchRequest)
    {
        this.SearchRequest = SearchRequest;
    }
}

The message contract class defines a public field named Priority that uses the string type and is marked with a MessageHeader attribute. Another public field named SearchRequest is added; it is defined as a SearchCriteria type and is marked with a MessageBodyMember attribute. The next code example shows how this message contract is used in a service contract.

[System.ServiceModel.ServiceContractAttribute(Namespace = 
     "http://EmployeeService/EmployeeService/2006/06", Name = "IEmployeeManager")]
public interface IEmployeeManager
{
    [System.ServiceModel.OperationContractAttribute(Action = "FindEmployee")]
    FindEmployeeResponse FindEmployee(FindEmployeeRequest request);

    [System.ServiceModel.OperationContractAttribute(Action = "GetEmployee")]
    GetEmployeeResponse GetEmployee(GetEmployeeRequest request);
}

The end result is that the SOAP schema generated using this message contract has an element named Priority that is added to the SOAP header and a SOAP body that contains a single element named SearchRequest, as shown in the following SOAP message.

<soapenv:Envelope
    xmlns:soapenv="https://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <tns:Priority
        xmlns:soapenc="https://schemas.xmlsoap.org/soap/encoding/"
        xmlns:tns="http://EmployeeService/EmployeeService/2006/06"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" />
   </soapenv:Header>
   <soapenv:Body>
      <tns:SearchRequest
          xmlns:soapenc="https://schemas.xmlsoap.org/soap/encoding/"
          xmlns:tns="http://EmployeeService/EmployeeService/2006/06"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xs="http://www.w3.org/2001/XMLSchema">
          <tns:EmployeeID>0</tns:EmployeeID>
          <tns:FirstName />
          <tns:LastName />
      </tns:SearchRequest>
   </soapenv:Body>
</soapenv:Envelope>

Notice that the SearchRequest element contains the fields that are defined in the SearchCriteria data contract. This example shows a single data contract that is not wrapped by other elements. Typically, this type of data contract is referred to as a message type and contains other data contracts. However, this example is simplified to show the relationship between data contracts, message contracts, and service contracts.

Controlling the Schema

The MessageContractAttribute has several different attributes that can be used to control the schema structure and namespaces. SOAP operations can have only one element in the associated SOAP body. When data types are used as parameters in a service contract, the default behavior is to wrap them with request elements and response elements in the SOAP body.

This wrapping happens regardless of how many data types are found in the request or response. However, when using something like a message type, which is nothing more than a data contract that holds all data contracts for a message request or response, the wrapping is not necessary or desired.

To understand how wrapping is controlled by the MessageContract attribute, it helps to compare the behavior to a WebMethod parameter named ParameterStyle, which is used by the XmlSerializer in ASMX services. For example, to prevent wrapping, you set the ParameterStyle to Bare. You can also force wrapping by using a ParameterStyle value of Wrapped; however, that is not required.

The MessageContractAttribute has an attribute named IsWrapped that indicates whether the data contracts should be wrapped. When IsWrapped is set to false, the data contracts used by a service contract will not be wrapped. When this value is set to true, the data contracts will be wrapped; in addition, you can also control the name and namespace used for the wrapper element when IsWrapped is set to true.

To put this into context, a message contract class can be used in two cases: it can be used when you use message types or when you use different namespaces for the data contracts that are used by the service contract.

With the first case, a message contract class is required so that wrapping can be disabled when message types are used. The default behavior of the service contract serializer is to wrap all data contracts that are used by a service contract with request elements and response elements. This behavior is not necessary when using message types; with the MessageContract attribute. In this case, the data contract serializer will not add the wrapper elements.

With the second case, a message contract class is required so that different namespaces can be used for the service contract and the data contracts. Without the use of a message contract class, the default serialization will not assign a namespace to the wrapper class. This will cause errors because the wrapper class needs to use the same namespace as the data contract classes. By using a message contract class, you can define the namespace that will be used by wrapper elements in the request and response message.