This is the Day 9 article. If you have not read the previous articles, please go through the following articles:
- Day 1 - WCF Introduction and Contracts
- Day 2 - WCF Fault Contracts
- Day 3 - WCF Message Exchange Patterns
- Day 4 - WCF DataContract
- Day 5 - WCF Difference between service application and service library
- Day 6 - WCF Serialization Part 1
- Day 7 - WCF Serialization Part 2
- Day 8- WCF Opt-In Vs. Opt-Out
Introduction
In this article we will discuss Message Contracts. We will also discuss MessageContractAttriubtes, MessageHeaderAttriubtes, MessageBodyMemberAttriubtes and a sample code demonstration.
In WCF services, a DataContract enables us to define the structure of the data. This data is sent in the body of our SOAP (Simple Object Access Protocol) messages. These messages may be of either inbound (request) or outbound (response) type. A message is nothing but a packet and WCF uses this packet to transfer information from source to destination. This message contains an envelope, header and body.
A Message Contract is used to control the structure of a message body and serialization process. It is also used to send / access information in SOAP headers.
Message Contract Attributes
- MessageContractAttribute
- MessageHeaderAttribute
- MessageBodyMemberAttribute
MessageContractAttribute
The MessageContract Attribute is applied to a class or structure to define our own message structure, as in:
[MessageContract()]
public class AuthorRequest
{
}
Properties of MessageContractAttribute
-
public bool HasProtectionLevel { get; }
HasProtectionLevel gets a value that indicates whether the message has a protection level.
It returns true if the message must be encrypted, signed, or both; otherwise false. The default is false.
-
public bool IsWrapped { get; set; }
IsWrapped gets or sets a value that specifies whether the message body has a wrapper element.
It returns true if the message body has a wrapper element; otherwise, false. The default is true.
-
public ProtectionLevel ProtectionLevel { get; set; }
ProtectionLevel gets or sets a value that specified whether the message must be encrypted, signed, or both.
It returns one of the System.Net.Security.ProtectionLevel values. The default is
System.Net.Security.ProtectionLevel.None.
-
public string WrapperName { get; set; }
WrapperName gets or sets the name of the wrapper element of the message body.
It returns the name of the wrapper element in the message body.
-
public string WrapperNamespace { get; set; }
WrapperNamespace gets or sets the namespace of the message body wrapper element.
It returns the wrapper element namespace.
For example:
[MessageContract(IsWrapped = false,ProtectionLevel=ProtectionLevel.None)]
public class AuthorRequest
{
}
MessageHeaderAttribute
MessageHeaderAttribute is applied to the members of the MessageContract to declare the members within the message header; see:
[MessageContract(IsWrapped = false,ProtectionLevel=ProtectionLevel.None)]
public class AuthorRequest
{
[MessageHeader()]
public string AuthorId;
}
Properties of MessageHeaderAttribute
-
public string Name { get; set; }
Name specifies the name of the element that corresponds to this member.
It returns the name of the element that corresponds to this member. This string must be a valid XML element name.
-
public string Namespace { get; set; }
Namespace specifies the namespace of the element that corresponds to this member.
It returns a namespace URI of the element that corresponds to this member.
-
public ProtectionLevel ProtectionLevel { get; set; }
ProtectionLevel specifies whether the member is to be transmitted as-is, signed, or signed and encrypted.
It returns one of the System.Net.Security.ProtectionLevel values. The default is System.Net.Security.ProtectionLevel.None.
-
public string Actor { get; set; }
Actor gets or sets a URI that indicates the node at which this header is targeted. It maps to the role header attribute when SOAP 1.2 is used and the actor header attribute when SOAP 1.1 is used.
It returns a URI that indicates the node at which this header is targeted. This URI maps to the role header attribute when SOAP 1.2 is used and the actor header attribute when SOAP 1.1 is used.
-
public bool MustUnderstand { get; set; }
MustUnderstand specifies whether the node acting in the System.ServiceModel.MessageHeaderAttribute.Actor role must understand this header. This is mapped to the mustUnderstand SOAP header attribute.
It returns true if the node acting in the System.ServiceModel.MessageHeaderAttribute.Actor role must understand this header; otherwise, false.
-
public bool Relay { get; set; }
Relay specifies whether this header is to be relayed to downstream nodes. This is mapped to the relay SOAP header attribute.
It returns true if this header is to be relayed to downstream nodes; otherwise, false.
MessageBodyMemberAttribute
MessageBodyMemberAttribute is applied to the members of message contracts to declare the members within the message body.
Properties of MessageBodyMemberAttribute
Name, Namespace, ProtectionLevel and Order are the properties of MessageBodyMemberAttribute. As we are now familiar with all the properties, I am not explaining here once again.
Why should we use MessageContract
Suppose we are not using MessageContract in our service, by default SOAP body element contains a child wrapper element of operation name and wraps parameters. If there is no parameter then this element will be empty in the inbound (request) message. In the same way, in an outbound (response) message, if it is of type void or say nothing to return then this element will be empty.
For example we create a service and set MessageContract with the property IsWrapped to false. Then there is no child element in the SOAP body. You will see a collection of MessageBodyMembers directly under the SOAP body within the MessageContract.
Controlling wrapping is important when we deal with the other platforms except WCF because they might serialize their SOAP messages differently.
Sample Code
Consider a scenario where we create a service and in this service we have one operation contract which returns the author information. Now we want to set some authentication like AuthorId should be matched. In this case we store AuthorId in MessageHeader because it is safe. Here we create two MessageContracts, one is for the request i.e. AuthorRequest and another is for the response i.e. AuthorResponse.
While creating a MessageContract consider the following two points:
-
When we pass a parameter of type MessageContract, only one parameter is used in the service operation.
-
The return type of the OperationContract is of MessageContractType or Void type.
Now add the following lines of code to your Interface.
Now add an implementation of the above operation contract in the service class.
Test Client Output (IsWrapped = false)
Insert 'db2972' as the input for the AuthorIdentity parameter; see:
SOAP Request
An AuthorIdentity element is in the SOAP request as we pass this under the MessageHeader. And the Body element is empty because we are not passing any value.
SOAP Response
In response we get author information directly under the body element as we set IsWrapped to false.
Test Client Output (IsWrapped = true)
Now change the code, set IsWrapped to true in the MessageContract and once again check the result in Test Client.
SOAP Request
AuthorRequest element is empty and is added under the body element because we set IsWrapped to true.
SOAP Response
In the same way in the response also the AuthorResponse element is added under the body element.
Conclusion
In this article I explained the IsWrapped property with an example. You can download the source code and check the output by changing other properties values. The ProtectionLevel property is very important and we will discuss it later on in future articles.