Wednesday, February 17, 2010

Notes on Programming WCF - Part I - Contracts


Excerpts on a great WCF book: "Programming WCF Services- by Juval Lowy"

Contracts
In WCF, all services expose contracts. The contract is a platform-neutral and standard way of describing what the service does. WCF defines four types of contracts:
1. Service contracts:
Describe which operations the client can perform on the service. Service contracts are the subject of the next chapter, but they are used extensively in every chapter in this book
2. Data contracts:
Define which data types are passed to and from the service.
1. Even if the DataMember attribute on the service side is applied on a private field or property, as shown here:
[DataContract]
struct Contact
{
[DataMember]
string FirstName
{get;set;}
[DataMember]
string LastName;
}
2. The imported definition will have a public property instead.
3. Do not apply the DataMember attribute both on a property and on its underlying field—this will result in duplication of the members on the importing side.
4. A type marked only with the DataContract attribute cannot be serialized using the legacy formatters. If you want to serialize such a type, you must apply both the DataContract attribute and the Serializable attribute on it. In the resulting data contract for the type, the effect will be the same as if only the DataContract attribute had been applied, and you will still need to use the DataMember attribute on the members you want to serialize.
5. Inferred data contracts are sometimes called POCO, or Plain Old CLR Object.
6. Data Contract Events
7. OnSerializing attribute designates a method to handle the serializing event
8. OnSerialized attribute designates a method to handle the serialized event
9. OnDeserializing attribute designates a method to handle the deserializing event
10. OnDeserialized attribute designates a method to handle the deserialized event
11. Failing to designate every level in the class hierarchy as serializable or as a data contract will result in an InvalidDataContractException at the service load time.
12. Known Types:
In traditional object-oriented programming, a reference to a subclass is also a reference to its base class, so the subclass maintains an Is-A relationship with its base class. Any method that expects a reference to a base class can also accept a reference to its subclass. This is a direct result of the way the compiler spans the state of the subclass in memory, by appending it right after the base class section. While languages such as C# let you substitute a subclass for a base class in this manner, this is not the case with WCF operations. By default, you cannot use a subclass of a data contract class instead of its base class.
13. Service Known Types:
14. Data Contract Equivalence:
Two data contracts are considered equivalent if they have the same wire representation—that is, if they have the same infoset schema. This can be the case if they define the same type (but not necessarily the same version of the type), or if the two data contracts refer to two different types with the same data contract and data member names. Equivalent data contracts are interchangeable: WCF will let any service that was defined with one data contract operate with an equivalent data contract.
15. Serialization Order:
16. Versioning:
1. New members
2. Missing members
3. Round-tripping
4. Using OnDeserializing() event
17. Required members:
18. Schema compatibility
While implementing IExtensibleDataObject enables round-tripping, it has the downside of enabling a service that is compatible with one data contract schema to interact successfully with another service that expects another data contract schema.
The best practice is to always have your data contracts implement IExtensibleDataObject and to avoid setting IgnoreExtensionDataObject to true. IExtensibleDataObject decouples the service from its downstream services, allowing them to evolve separately.
Unlike ignoring new members, which for the most part is benign, the default handling of missing members may very likely cause the receiving side to fail further down the call chain, because the missing members may be essential for correct operation. This may have disastrous results. You can instruct WCF to avoid invoking the operation and to fail the call if a data member is missing by setting the IsRequired property of the DataMember attribute to true. When, on the receiving side, DataContractSerializer does not find the information required to de-serialize a member marked as required in the message, it will abort the call, resulting in a NeTDispatcherFaultException on the sending side.
3. Fault contracts:
Define which errors are raised by the service, and how the service handles and propagates errors to its clients.
4. Message contracts:
Allow the service to interact directly with messages
1. MaxReceivedMessageSize defaults to 64K. While this is adequate for simple services, services that have many endpoints that use complex types will generate larger messages, causing the call to MetadataExchangeClient.GetMetadata( ) to fail. My experimentations indicate that 5 is an adequate fudge factor for most cases.

No comments:

Post a Comment