Here at Conchango we have community days every six weeks where we get together to discuss common work interests. As a .Net Architect, one of the core communities I participate in is the .Net community. At our last community day, I presented on Windows Communication Foundation, a technology I have been working with in anger now for over a year.
Whilst the PowerPoint slideshow doesn't really cover any detail on what I presented or demonstrated, I thought I'd attach it to this blog anyway, as this blog covers the contract design guidelines I ran through with the community.
The following design guidelines can mostly be based around one single important fact about implementing a service orientated architecture (SOA); changing the design of a contract is in an expensive exercise. If changes in contract designs can be limited to a minimum, the cost of ownership of your SOA will reduce, because calling clients have to change less often.
Do all you can to design service contracts to be binding agnostic
This sounds like a simple point to make, but it's an easy one to forget, and difficult to achieve. The bottom line is that to get the most out WCF from an architect's perspective, you really want to try to ensure that non-functional requirements related to your communication needs do not become hard coded into your contract designs; if you can use configuration to drive transport, policy and encoding decisions, the cost of changing these features later becomes much cheaper than changing code.
This can be hard and at times impossible to achieve. For example, if you decide that you need to use MSMQ integration binding, your service contract will need to use the MsmqMessage<T> class as the only argument allowed in your service operation, and thus your service contract is effectively hard wired to this binding type.
However, with other examples, you can design your contracts in an agnostic way. For example, you may choose to use the Session features of WCF, and could use the IsInitiating and IsTerminating properties of the OperationContractAttrbute in your design to enforce the opening and closing of sessions. Whilst this feature is useful, it will tie you into not being able to use BasicHttpBinding, and thus if you decide later that this binding best suits your communication needs, you will need to change the design of your service contracts accordingly.
Design request data contracts to act as an envelope to service requests
As mentioned above, MsmqIntegration binding requires dedicated service contracts using the MsmqMessage<T> class. If you design a service contract for a web service, but later decide to change this into a service that receives a message from a message queue, you will need to use MsmqMessage<T>, where T is the type of a single data contract.
Consider the following service operation:
int MultiplyNumbers(int firstNumber, int secondNumber);
If you choose to implement this using MsmqIntegration binding, you will need to create an envelope data contract, with properties for the first and second numbers. To avoid having to redesign data contracts later, always wrap multiple arguments into a single request data contract, such as:
int MultiplyNumbers(MultiplicationRequestData request);
Fault contracts require two way communication
Obvious when you think about it, but if you expect service faults to be reported to the calling client, the service operation must use two way communication.
Avoid contract namespace conflicts with the application layer
Be careful how you name you data contracts, because you will normally be wrapping an application with its own API, and this can lead to namespace conflicts which require you to use a fully qualified namespace on every call to the type, which mean messy code. On my project, we have adopted a standard of using EntityNameData as the naming convention for data contracts.
Always assign dates to your schema namespaces
This is important for schema versioning in your contracts, and particularly important in you are planning you use your services with a messaging hub, such as BizTalk Server where subscription is driven off of unique schema namespaces.
Only use types that translate to XSD types in your data contracts
Data contracts should only use types that have a direct comparison in XSD, because you WSDL will otherwise contain XSD import statements to Microsoft generated schemas to represent .Net types. This means using arrays instead of collections, and sticking to enumerations, integers, strings and datatimes.
Do not take an Object Orientated approach
Remember when you are designing a data contract that it is a schema, not an object model. This means that whilst the entities in your application are likely to use inheritance, this approach does not make sense for the generated schema you are creating. Always review your generated schema using svc util to ensure that the contracts create a clean WSDL with clean XSD schemas.
Implement ordering in your data contracts
Ordering is an optional parameter of the DataContractAttribute that controls the order of elements as they appear on the XSD schema that is produced as a result of designing a data contract. If you do not specify order, the schema will be generated in alphabetical order. The affect of this is that newly added elements do not necessarily appear at the end of the schema, which can make altering related artifacts (such as BizTalk maps) more problematic.
Data contracts should define type, not business rules
It is not an in built part of WCF of define validation rules within schema (the data contract), but I am commonly asked how to extend WCF data contracts to validate properties. The reason that WCF does not support XSD restrictions through data contracts out of the box is that implementing business rules through schema design is an expensive way to implement business rules, because if a rule changes, the schema must be changed, and thus calling clients must be made aware of the change. A better way to implement business rules is within the service implementation itself. The data contract should only define the types allowed to be used by the service. This way, changes in business rules do not affect contract designs and services become cheaper to maintain going forward.