WCF Contracts
Understanding Service Contracts
Service contracts define the agreement between a WCF service and its clients. They specify the operations that the service exposes, the messages exchanged, and the data types used. In WCF, service contracts are defined using the ServiceContractAttribute and the OperationContractAttribute.
Defining a Service Contract
You can define a service contract in two primary ways:
- Using Attributes: The most common approach is to apply the
[ServiceContract]attribute to an interface or a class, and then apply the[OperationContract]attribute to the methods that should be exposed as service operations. - Using a Configuration File (less common for defining the contract itself): While contracts are primarily defined in code, configuration files play a crucial role in binding these contracts to endpoints and specifying their communication details.
The ServiceContractAttribute
This attribute marks an interface or class as defining a WCF service contract. Key properties include:
Namespace: Specifies the XML namespace for the contract.Name: Specifies the name of the contract in the metadata.
The OperationContractAttribute
This attribute marks a method within a service contract as an exposed operation. Key properties include:
IsOneWay: Indicates if the operation is a one-way message (no return value expected).IsInitiating: Specifies if the operation can start a new session.IsTerminating: Specifies if the operation is the last in a session.Action: Explicitly defines the SOAP Action for the operation.
Here's a simple example:
[ServiceContract(Namespace = "http://microsoft.com/contoso")]
public interface ICalculator
{
[OperationContract]
int Add(int a, int b);
[OperationContract]
int Subtract(int a, int b);
[OperationContract(IsOneWay = true)]
void LogOperation(string message);
}
Data Contracts
Data contracts define the structure of the data that can be sent and received by WCF services. They control how .NET types are serialized and deserialized into XML or other formats. Data contracts are defined using the DataContractAttribute and the DataMemberAttribute.
Defining a Data Contract
Similar to service contracts, data contracts are typically defined in code.
The DataContractAttribute
This attribute marks a class or structure as a data contract. Key properties include:
Namespace: Specifies the XML namespace for the data contract.Name: Specifies the name of the data contract in the metadata.
The DataMemberAttribute
This attribute marks a public property, field, or event of a data contract class as a member that should be serialized.
Name: Specifies the name of the member in the serialized format.Order: Specifies the order of the member in the serialized format.IsRequired: Indicates if the member is mandatory.
Example of a data contract:
[DataContract(Namespace = "http://microsoft.com/contoso/datatypes")]
public class CalculationResult
{
private int resultValue;
private string operationPerformed;
[DataMember]
public int Result
{
get { return resultValue; }
set { resultValue = value; }
}
[DataMember(Name = "Operation")]
public string Operation
{
get { return operationPerformed; }
set { operationPerformed = value; }
}
}
[DataMemberAttribute]. This provides fine-grained control over what data is exposed.
Message Contracts
Message contracts allow you to have complete control over the structure of the SOAP message. They are useful when you need to customize headers, specify a specific message format, or create complex message bodies that go beyond simple data contract serialization.
The MessageContractAttribute
This attribute marks a class as defining a WCF message contract. Key properties include:
IsWrapped: Controls whether the body is wrapped with an element representing the operation name.
The MessageHeaderAttribute
Applied to properties within a message contract class to define message headers.
The MessageBodyMemberAttribute
Applied to properties within a message contract class to define members of the message body.
A basic message contract example:
[MessageContract]
public class AddRequest
{
[MessageHeader]
public string ClientId;
[MessageBodyMember]
public int A;
[MessageBodyMember]
public int B;
}
[MessageContract]
public class AddResponse
{
[MessageBodyMember]
public int Result;
}
Contract-First Development
In contract-first development, you design your WCF contracts (service, data, and message contracts) first, often by generating an XML Schema Definition (XSD) or Web Services Description Language (WSDL) file. Then, you generate the C# code for your service and client from these contract definitions.
This approach is valuable for:
- Promoting interoperability between different platforms and languages.
- Establishing clear agreements before implementation begins.
- Ensuring that the service contract is the single source of truth.
Tools like xsd.exe (for XSD to C# classes) and svcutil.exe (for WSDL to service/client code) are instrumental in contract-first development.