Export (0) Print
Expand All

Things to Consider When Designing a WCF Contract

.NET Framework 4

Applies to: Windows Communication Foundation

Published: June 2011

Author: Bill Collette

In WCF, a good service design requires good contracts. What makes a good WCF service contract? If you ask the top 10 WCF developers in the world, you may get 10 different answers. However, one answer that most would agree with is that a good contract allows you to meet your requirements. There is already a great deal of reference material available to help you define service contracts. You can start with "Defining Service Contracts" on MSDN at http://msdn.microsoft.com/en-us/library/ms733070.aspx.

This article discusses some additional considerations such as inheritance and generics, as well as contract segmentation. It also expands on some issues that deserve extra attention.

If you use generics in your contract design, remember that they are part of the .NET Framework. The metadata that describes your service does not appear as a generic class. Generics are a .NET construct and are not understood by the interoperable consumers of your service. Once it is generated, the name of your type will look something like ClassNameOfYourType, and have a generated hash at the end of it. In a real-world scenario, this name is unintelligible to the consuming clients, and it can produce unintended results when the Web Services Description Language (WSDL) is generated.

Still, from the perspective of object-oriented development, generics can be helpful. To use them, you should control how the proxy is generated and explicitly add a name and namespace for your contract.

For example, if you want all of your services to inherit similar behaviors and/or to contain consistent data elements, you can build a base class that encapsulates these qualities. You can then implement a service that inherits from this class.

The following code show a service that inherits from the CompositeBase class and also implements the IService1 interface. The base class has a namespace as well as a name that is defined within its data contract attribute. This code defines the base class.

[DataContract(Namespace = "http://mycompany/services/contracts", Name = "CompositeBase")]
    public abstract class CompositeBase<T> where T : class
    {        public T GetMySubType
        {            get {return default(T);}
        }        public abstract bool Validate();

        [DataMember(Name = "ClientName", IsRequired = true)]
        public string ClientName { get; set; }
        
    }

This code defines a service that inherits from the base class.

public class Service1 : CompositeBase<Service1>, IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }
    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite == null)
        {
            throw new ArgumentNullException("composite");
        }
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }

    public override bool Validate()
    {
        //perform some validation
        return true;
    }
}

A new WCF project contains an interface and an implementation. By default, the interface contains an OperationContract attribute and a DataContract attribute. These show you some of the options that you can include in your contracts. The service works correctly at the outset, but you often need to refactor it to accommodate your scenario. It is also probable that your project will require several different kinds of data elements.

When you set up your project, there are several good practices to follow that will help you to organize your contracts and interfaces. These practices will also help you when you create unit tests, and to work with other services and their contracts.

The following illustration shows the default WCF project.

Referenced Image

The first recommendation is to separate logically related interfaces, contracts, entities, messages, and enumerations into a separate project. One way to do this is to add a class library project to your solution and name it after your service name, with the word "Contracts" appended to it. An example of this is WcfService1.Contracts.

The second recommendation is to organize your data contracts into separate folders and namespaces. Any data contract that is a type of request or response is logically considered a type of message and can be placed inside a folder named Messages. Any data contract that is an entity or that resembles a data transfer object (DTO), can be placed inside a folder named Entities. You can also separate enumerations into a folder called Enumerations. Good organization is important, especially when there are many contracts. After your code is organized, make sure that your namespaces reflect the folder name and path in which they are located.

Another benefit to a logical organization is that it helps clarify what type of data contract you (or other developers) are referencing, whether from other projects or in unit tests. Organizing data contracts according to their type is a example of the PIE principle (Program Intently and Expressly).

The following illustration shows a WCF project that contains a contract-specific project. It is organized according to the best practices discussed in this section.

Referenced Image

It is important to add names and namespaces to your DataContracts when you design contracts. This practice ensures that the proxy is generated correctly when your code relies on inheritance and generics. When you set up a solution in the Microsoft® Visual Studio® development system, logically organize your DataContracts into separate folders. Also, physically separate your contracts into a separate project. These organizational best practices help to maintain namespaces that are comprehensible, and makes it easy to reference your contracts from other projects. They also make unit testing easier.

For more information, see the following resources:

Previous article: WCF Architecture Considerations

Continue on to the next article: Service-to-Service Interactions

Show:
© 2014 Microsoft