WCF contract guidelines

Designing WCF services means you have to specify the contracts of the functionality that you want to expose. This blog entry contains some notes about the guidelines I follow.

Be explicit

The Name and Namespace properties control the name and namespace of the elements in the WSDL. Especially namespace is important because when you send SOAP messages, the elements need to be namespace qualified so that they can be serialized/deserialized correctly.

Namespaces follow the URI format, like http://schemas.dunatis.be, but are not actual addresses – they just represent the domain of your company, which is guaranteed to be unique.

In general, I recommend to:

  • explicitly specify the Name property, as to clearly distinguish the internally used names from the ones that will be exposed publically. Changing an internal property name will then not break the contract!
  • explicitly specify the Namespace property, because if you don’t specify the namespace, it defaults to http://tempuri.org – so it’s recommended to specify you own namespace – one that is relevant to your application.
  • explicitly specify the IsRequired property
  • explicitly specify the Order property, because if you don’t, the schema will be generated in alphabetical order. As a result, if you add new properties they will not appear at the end of the schema, which may cause issues.

Strict versus lax versioning

If you don’t have control over the clients that consume your service, you have to assume that contract changes would break their implementation. After all, a contract change means that the XML message changes, and clients may not be able to deal with that. In that case, use strict versioning, so that the original contract is not changed and instead, a new version is created and made available.

On the other hand, if you control the clients, you may choose lax versioning, and in this case you are allowed to modify the existing contract (in a non-breaking way) because it won’t break the clients using it.

For versioning I use a date indication yyyy/mm instead of version number, because it’s a W3C standard and it has more meaning.

Here’s a nice article that discusses versioning rules in detail. And this series is an excellent explanation about versioning strategies: part 1, part 2 and part 3.

Case sensitivity

Important to notice is that when contracts are processed, the WCF infrastructure is case-sensitive to both the namespaces and the names of data contracts and data members. Therefore I use:

Of course, this is personal taste.

Examples

Service contracts

[ServiceContract(Name = "CustomerService",

Namespace = "http://schemas.dunatis.be/2012/08")]
public interface ICustomerService
{
[OperationContract(Name = "GetCustomerDetails")]
GetCustomerDetailsResponse GetCustomerDetails(

GetCustomerDetailsRequest request);
}

The service contract has an explicit name and namespace. Namespace also has a version specification; this allows me to have a second version of the service later on in case breaking changes were needed in the contract (strict versioning).
 
The operation contract has an explicit name.
 

Message contracts

[MessageContract(WrapperName = "GetCustomerDetailsRequest",
WrapperNamespace =

"http://schemas.dunatis.be/customer/getcustomerdetailsrequest/2012/08")]
public class GetCustomerDetailsRequest
{
[DataMember(Name="Customer", IsRequired=true, Order=0)]
public Customer Customer { get; set; }
}

The message contract has an explicit wrapper name and namespace. Namespace also has a version specification.

The data members have an explicit name, and also Order and IsRequired are specified.

Data contracts

[DataContract(Name = "Customer", 
Namespace = "http://http://schemas.dunatis.be/customer/2012/08")]
public class Customer
{
[DataMember(Name = "FirstName", IsRequired = true, Order = 0)]
public string FirstName { get; set; }
}

The data contract has an explicit name and namespace. Namespace also has a version specification.

The data members have an explicit name, and also Order and IsRequired are specified.

Service implementation

[ServiceBehavior(Name = "CustomerService",
Namespace = http://schemas.dunatis.be)]
public class CustomerService : ICustomerService
{
public GetCustomerDetailsResponse GetCustomerDetails(

GetCustomerDetailsRequest request)
{
throw new NotImplementedException();
}
}

The service behavior has an explicit name and namespace.
 

Using constants

Instead of writing every namespace multiple times as a string, you could define constants and use these. Using the constant ensures that the namespace is the same for the contract and the service. If you make it available in a shared library, it also remains consistent across all of your projects/services/solutions.

public class NamespaceConstants
{
// Ensures consistency in the namespace declarations across services
public const string Namespace = “http://schemas.dunatis.be/2012/08;
}

[ServiceContract(Name = "CustomerService",             
Namespace = NamespaceConstants.Namespace)]
public interface ICustomerService
{
[OperationContract(Name = "GetCustomerDetails")]
GetCustomerDetailsResponse GetCustomerDetails(
GetCustomerDetailsRequest request);
}

 
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s