In this article, we will discuss the message contract (CONTRACT), one of the four WCF contracts (service contracts, data contracts, message contracts, and error contracts). The service contract focuses on the description of the service operation, which focuses on the description of the data structure and format, while the message contract focuses on the matching relationship between the type member and the message element.
We know that only serializable objects can be passed between the client and the server through a service invocation. So far, There are two kinds of serializable types we know: one that uses the System.SerializableAttribute attribute or the type that implements the System.Runtime.Serialization.ISerializable interface, and the other is the data contract object. For service operations based on these two types, The client formats the input parameters into the request message through System.ServiceModel.Dispatcher.IClientMessageFormatter, and the input parameters are placed in the body of the message as a payload; Similarly, the execution result of the service operation is System.serv IceModel.Dispatcher.IDispatchMessageFormatter as the body of the reply message after serialization.
In some cases, there is a requirement that when serializing an object and generating a message, you want to include some of the data members as the header of soap, partly as the body of the message. For example, we have a service operation in the flow of the file upload, in addition to streaming in binary representations of the contents of the file, but also need to transfer an additional file based on the attributes of information, such as file format, file size and so on. The general practice is to pass the stream of the contents of the file as the body of soap, passing its property content as a SOAP header. Such a function can be implemented by defining a message contract.
Definition of a message contract
The message contract, like the data contract, is defined on the data, not the function type. However, the data contract is designed to define the structure of the data (match the data type with the XSD), while the message contract focuses more on the representation of the members of the data in the SOAP message. The message contract is defined by the following 3 features: System.ServiceModel.MessageContractAttribute, System.ServiceModel.MessageHeaderAttribute, System.ServiceModel.MessageBodyMemberAttribute. MessageContractAttribute apply to types, Messageheaderattribute and Messagebodymemberattribute are applied to attributes or field members. Indicates whether the corresponding data member is a member based on a SOAP header or a member of a SOAP principal. Let's start with a brief introduction to these 3 features:
1, MessageContractAttribute
By applying messagecontractattribute to a class or struct (Struct) to make it a message contract. From the definition of MessageContractAttribute, MessageContractAttribute generally has the following two types of attribute members:
ProtectionLevel and Hasprotectionlevel: Represents the level of protection that has been briefly described in the service contract, and the protection level of the message is defined by the System.Net.Security.ProtectionLevel enumeration in WCF. There are generally 3 optional levels of protection: None, sign, and EncryptAndSign
iswrapped , Wrappername , Wrappernamespace: iswrapped The meaning of the expression is whether to add an extra root node for the defined principal member (one or more). Wrappername and Wrappernamespace represent the name and namespace of the root node. The defaults for iswrapped, Wrappername, and Wrappernamespace are true, type names, and http://tempuri.org/respectively.
1: [AttributeUsage (Attributetargets.struct | AttributeTargets.Class, AllowMultiple = False)]
2:public Sealed class Messagecontractattribute:attribute
3: {
4: //other Members
5: Public bool hasprotectionlevel {get;}
6: Public protectionlevel protectionlevel {get; set;}
7:
8: Public bool iswrapped {get; set;}
9: Public string wrappername {get; set;}
Public string wrappernamespace {get; set;}
11:}
The following code makes the customer type a message contract by applying MessageContractAttribute. The ID and name attributes are defined as message header (header) members by applying Messageheaderattribute, and the Address property is defined by Messagebodymemberattribute as a message body member. The following XML represents the representation of the customer object in the SOAP message.
1: [MessageContract]
2:public class Customer
3: {
4: [MessageHeader (Name = "Customerno", Namespace = "http://www.artech.com/")]
5:public Guid ID
6: {get; set;}
7:
8: [MessageHeader (Name = "CustomerName", Namespace = "http://www.artech.com/")]
9:public string Name
{get; set;}
11:
[Messagebodymember (Namespace = "http://www.artech.com/")]
13:public string Address
: {get; set;}
15:}
1: <s:envelope xmlns:a= "http://www.w3.org/2005/08/addressing" xmlns:s= "Http://www.w3.org/2003/05/soap-envelope" ">
2: <s:Header>
3: <a:action s:mustunderstand= "1" >http://tempuri.org/IOrderManager/ProcessOrder</a:Action>
4: 5: 6: </s:Header>
7: <s:Body>
8: <customer xmlns= "http://tempuri.org/" >
9: <address xmlns= "http://www.artech.com/" > #328, Airport Rd, Industrial Park, Suzhou Jiangsu, Province< ;/address>
: </Customer>
One: </s:Body>
</s:Envelope>
If we set the Iswrapped property to False, the customer node that is set outside the address node will be removed from the SOAP message.
1: [MessageContract (iswrapped = False)]
2:public class Customer
3: {
4: //ellipsis member
5:}
1: <s:envelope xmlns:a= "http://www.w3.org/2005/08/addressing" xmlns:s= "Http://www.w3.org/2003/05/soap-envelope" ">
2: ...
3: <s:Body>
4: <address xmlns= "http://www.artech.com/" > #328, Airport Rd, Industrial Park, Suzhou Jiangsu, province</ Address>
5: </s:Body>
6: </s:Envelope>
We can also customize the naming and namespaces of this principal envelope (wrapper). Let's set the Wrappername and Wrappernamespace properties of MessageContractAttribute to Cust and http://www.artech.com/.
1: [MessageContract (iswrapped = true, Wrappername = "Cust", Wrappernamespace = "http://www.artech.com/")]
2:public class Customer
3: {
4: //ellipsis member
5:}
1: <s:envelope xmlns:a= "http://www.w3.org/2005/08/addressing" xmlns:s= "Http://www.w3.org/2003/05/soap-envelope" ">
2: ...
3: <s:Body>
4: <cust xmlns= "http://www.artech.com/" >
5: <Address> #328, Airport Rd, Industrial Park, Suzhou Jiangsu province</address>
6: </Cust>
7: </s:Body>
8: </s:Envelope>