Service Contracts by default, can handle simple service calls. Calls which
can have simple type arguments(Int, string,etc..), and which return also
simple types values. The problem comes when you want to return a complex
type, or accept it as an argument for your service operation.
In order to do that, the messaging world, has a concept called Data
Contract. Data Contract is the normalization of your custom messaging
structures. It defines the members of your operation arguments or return
values. In WSDL, the Data Contract is equivalent to the type element
In WCF, Data Contracts are defined through classes instead of interfaces
like Service Contracts. Those classes are decorated with an attribute named
DataContract, and members that should be considered part of the message,
should be decorated with DataMember attribute.
Let's assume you had a service named MembershipService, having an operation
named GetUserDetails like this:
public class MembershipService
{
public User GetUserDetails(int userId)
{
//internal logical to get the User details.
}
}
In order to normalize the User serialization on the wire, you needed to
decorate your User class with some attributes like this:
[DataContract]
public class User
{
[DataMember]
public string Name;
[DataMember]
public string Address;
//..etc..
}
You might wonder, why you have to decorate your class, since in the past,
this was not needed (ASMX web services, for example). Well, as best
practice, maybe you should be doing it in the past, with Xml attributes,
but, by default, the framework was serializing types to the wire, if it
could handle with that serialization.
WCF, oppositely, assumes that nothing is exposed by default. So, if you're
class is not decorated with Data Contract attributes, WCF doesn't allow
serialization to the wire. This is very important, since it's a completely
change on exposing information, giving explicit control of what's being sent
on the message to the developer.
Another feature of WCF Data Contracts, is the option to define
Required/NonRequired data members. This is done with a property named
IsRequired on DataMember attribute. Using this property, you can define if a
member is mandatory when receiving a message using a Data Contract.
As an example, let's assume you have another operation in your
MembershipService, named AddUser:
public int AddUser(User userDetails)
{
//add the user and return the userId inserted;
}
If your application demands that the user Name field is required, but
Address is not, you could decorate the User Data Contract, in order to power
WCF to decide if a valid message arrives to your service, before calling it.
So, in order to implement this validation, your User Data Contract, would
look like this:
[DataContract]
public class User
{
[DataMember(IsRequired=true)]
public string Name;
[DataMember(IsRequired=false)]
public string Address;
//..etc..
}
In WCF September CTP, the VersionAdded property was apparently removed. In
past WCF CTP versions, this property was telling to the infrastructure in
which version the data member was added to the data contract, so message
validation could occur considering data versions.
My opinion is that this was too confusing and unnecessary, so maybe the WCF
team removed the property also considering the same. I think IsRequired
property can handle all this, if your service doesn't require new properties
that did not exist in the past. If it does, then your contract must be
changed.
Let's assume that your User Data Contract, was in version 2 of your app,
needing a mandatory field named Phone. If this happens, you're breaking the
contract with your consumers. Old consumers should have knowledge of this
change, and, unfortunately, old calls will not work anymore.
Don't forget that in SOA, contracts should be built to last, so the above
situation should be avoided when possible. If your new Phone field was not
necessary to your normal service execution, than, in my opinion, you don't
need deprecated VersionAdded property, and you can handle this with
IsRequired property.
A final comment is going to differences between data contracts and domain
types (ex: data access classes). Don't forget that, in order to avoid
maintenance problems in the future, your internal implementation classes
should not be exposed as data contracts, and a mapping between both should
occur before and after service execution, giving independence to both. If
you're new to this best practice, I'll recommend "Messaging Mapper" (477)
from "Enterprise Integration Patterns" (0-321-20068-3)