Search This Blog

Wednesday, November 28, 2012

WCF Contract:



What is Contract In General?
A contract is an agreement entered into voluntarily by two parties or more with the intention of creating a legal obligation, which may have elements in writing, though contracts can be made orally. The remedy for breach of contract can be "damages" or compensation of money.
  Wording of Contract need to be precise to avoid multiple interpretations, it should clearly mention role of each participating party.
What is WCF TERM CONTRACT?
WCF is framework for creating Service Oriented Applications in Microsoft dot net. In Service Oriented environment different software component communicate with each other. These component may be present on different platforms, may be using dissimilar technologies so streamline the process of communication there need to mutually agreed platform independent way of describing what functionality given wcf service offers to others for consumption & how it can be consumed. In Broader term WCF Contract is this agreement.
WCF uses term contract in reference to
1)      Defining service and its operations
2)      To explain data which are transferred by wire
In WCF there are three types of contracts Service contracts, Data Contracts & Message Contracts.
Service Contract:
WCF Service contract defines the functionality which is exposed by wcf service to outside world. A WCF Service can have more than one service contract but it should have at least one Service contract.
   Service contracts are defined by applying the ServiceContractAttribute and OperationContractAttribute to an interface or class. Using interface instead of class supports the separation of metadata from implementation for sharing libraries, and makes it possible for a service to implement multiple contracts.
ServiceContract attribute is similar to the WebService attribute in the ASMX WebService and OpeartionContract is similar to the WebMethod in ASMX WebService.
It is advisable to provide a namespace for the service contract. The default namespace is http://tempuri.org. Namespace should be usually consistent across all service contracts for the application. It can be any string but is traditionally a URI representative of the company or application domain and includes a year and month to support versioning scenarios.
The ServiceContractAttribute and OperationContractAttribute expose a Name property for providing explicit names for contracts and service operations; explicit naming of service & its operation prevents problems that may occur after re-factoring the interface or its method names.

A SERVICE CONTRACT USING EXPLICIT NAMING:
[ServiceContract(Name="ISimpleService",Namespace="urn:WCFEssentials/Samples/2008/12")]
public interface ISimpleService
{
    [OperationContract (Name="SendMessage")]
    string SendMessage(string message);
}
In the Callback scenario the service needs to get notified that some events have been happened to its client. The callback operations are part of the service contract. A service contract can have at most one callback contract. Once defined, the clients are required to support the callback. CallBack contract is useful when we want to call method of client from service.

Implementing a callback contract
Callback contracts should only expose one-way operations as it prevents deadlocks in a single-threaded service.
[ServiceContract(Name="ISimpleService", Namespace="urn:WCFEssentials/Samples/2008/12", CallbackContract=typeof(ISimpleServiceCallback))]
public interface ISimpleService
{
    [OperationContract (Name="SendMessage")]
    void SendMessage(string message);
}
[ServiceContract(Namespace = "urn:WCFEssentials/Samples/2008/12")]
public interface ISimpleServiceCallback
{
    [OperationContract(Name = "Callback", IsOneWay=true)]
    void Callback(string message);
}

Naming conventions for service operation parameters and return types can be controlled using the MessageParameterAttribute .
Controlling parameter and return value naming conventions
[ServiceContract(Name="ISimpleService", Namespace="urn:WCFEssentials/Samples/2008/12")]
public interface ISimpleService
{
    [OperationContract (Name="SendMessage")]
    [return:MessageParameterAttribute(Name="MessageOut")]
    string SendMessage([MessageParameterAttribute(Name = "MessageIn")]string message);
}
Understanding MessageParameterAttribute:
The MessageParameterAttribute, defined in the System.ServiceModel namespace, it shows the names of any operation parameters and return values. This attribute cannot be used with Message or message contracts.

This attribute has only one property, the Name property

[OperationContract()]
[return: MessageParameter(Name = "responseString")]
String SomeOp([MessageParameter(Name = "string")]string s);
In the above code
MessageParameterAttribute is used with this parameter to control how both the parameter and return values are serialized to XML request and response elements at the transport layer.
we need to use the Name property because the variable name as is cannot be used in the target programming language.
Data Contracts
A data contract is a formal agreement between a service and a client that abstractly
Data contract maps a CLR type to an XML Schema, defines how data types are serialized and deserialized. It also describes the data to be exchanged.
Data contract can be explicit or implicit. It defines which data types are passed to and from the service. WCF defines implicit contracts for built-in types such as int and string.
Data contracts are defined with the DataContractAttribute and DataMemberAttribute. Both the DataContractAttribute and DataMemberAttribute expose a Name property that is useful for providing explicit names for complex types and properties, respectively.
We need to include System.Runtime.Serialization reference to the project. This assembly holds the DataContract and DataMember attribute.
On client side proxy of class exposed in data contract can be created and utilized.
Recommended practices for data contract implementations
[DataContract(Namespace = "urn:WCFEssentials/Schemas/2008/12")]
public class LinkItem
{
    [DataMember(Name = "Id", IsRequired = false, Order = 0)]
    public long Id { get; set; }
    [DataMember(Name = "Title", IsRequired = true, Order = 1)]
    public long Title { get; set; }
    [DataMember(Name = "Description", IsRequired = true, Order = 2)]
    public long Description { get; set; }
    [DataMember(Name = "DateStart", IsRequired = true, Order = 3)]
    public DateTime? DateStart { get; set; }
    [DataMember(Name = "DateEnd", IsRequired = false, Order = 4)]
    public DateTime? DateEnd { get; set; }
    [DataMember(Name = "Url", IsRequired = false, Order = 5)]
    public string Url { get; set; }
}

What is CollectionDataContractAttribute ?


If we need to create a custom collection type with reference to above code the CollectionDataContractAttribute should be used instead of the DataContractAttribute.This attribute can be applied only to types that are recognized by the DataContractSerializer as valid, serializable collections.
The ItemName property enables us to control the names of the repeating items inside a collection.
CollectionDataContractAttribute applied to List<T>
[CollectionDataContract(Namespace = "urn:WCFEssentials/Schemas/2008/12",
ItemName="MyItemName")]
public class MyStrings: List<string>{}
[CollectionDataContract(Namespace = "urn:WCFEssentials/Schemas/2008/12",
KeyName="MyKeyName", ItemName = "MyItemName", ValueName = "MyValueName")]
public class MyDictionary : Dictionary<string, string> {}
Enumerations do not require any attributes to be serializable – however you can apply the DataContractAttribute if you want to control naming convention for enum members, or exclude an enum element from the public contract.
    Code below illustrates suppressing one enum element by applying the DataContractAttribute to the enumeration type and applying the EnumMemberAttribute to opt-in only two of the three enum elements.
Suppressing enum elements from the public contract
[DataContract(Namespace = "urn:WCFEssentials/Schemas/2008/12")]
public enum LinkItemCategory
{
  [EnumMember]
  Whitepaper,
  [EnumMember]
  Article,
  Webcast
}

Serializable Types

Although you should try to employ data contracts in your service contracts, types marked with the SerializableAttribute are supported by the DataContractSerializer.
Figure 11: A complex types marked with the SerializableAttribute
[Serializable]
public class LinkItem
{
    private long m_id;
    private long m_title;
    private long m_description;
    private DateTime? m_DateStart;
    private DateTime? m_DateEnd;
    private string m_url;
    // property accessors
}
You should note the following about serializable types:
  • The resulting serialization is wire-format – which means that all fields are serialized regardless of their accessibility.
  • Serializable types can participate in type hierarchies with data contracts.
  • Types can be marked with the SerializableAttribute as well as the DataContractAttribute. This is useful if the type is used in service contracts as well as serialized by other parts of the .NET Framework such as the ASP.NET session.


XmlSerializer

When we migrate ASMX service implementations to WCF and we might have a number of predefined complex types in assemblies that we want to leverage intact with the new implementation.
Since ASMX services rely on the XmlSerializer to serialize those complex types, we need our WCF services to use the XmlSerializer. This can be done by applying the XmlSerializerFormatAttribute
[ServiceContract(Namespace = "urn:WCFEssentials/Samples/2008/12")]
[XmlSerializerFormat]
public interface IArticlesManagerService
{
  [OperationContract]
  void AddArticleLink(LinkItem item);
  [OperationContract]
  List<LinkItem> GetArticleLinks();
}
this approach also means that complex types decorated with XmlSerializer attributes such as the XmlElementAttribute and XmlAttributeAttribute will serialize as expected.
Another case where the XmlSerializer may be useful is when you need greater control over the XML schema generated for a complex type. The XmlSerializer XmlElementAttribute lets you choose from three XSD schema date and time types – date, time, or dateTime – while the DataContractSerializer only supports dateTime.
A complex type decorated with XmlSerializer attributes
[XmlRoot(Namespace = "urn:WCFEssentials/Schemas/2008/12")]
public class LinkItem
{
    [XmlElement(IsNullable = false, Order = 0)]
    public long Id {get; set;}
    [XmlElement(IsNullable = false, Order = 1)]
    public string Title {get; set;}
    [XmlElement(IsNullable = false, Order = 2)]
    public string Description {get; set;}
    [XmlElement(DataType = "date", IsNullable = false, Order = 3)]
    public DateTime DateStart {get; set;}
    [XmlElement(DataType = "date", IsNullable = false, Order = 4)]
    public DateTime DateEnd {get; set;}
    [XmlElement(IsNullable = false, Order = 5)]
    public string Url {get; set;}
    [XmlIgnore]
    public string Tags {get; set;}
}
Another XmlSerializer attribute, the XmlAttributeAttribute, supports mapping public fields or properties to XML attributes instead of XML elements – something not supported by the DataContractSerializer. Typically this level of detail is not critical if you are starting from scratch, but it is relevant when you have existing XSD schemas to which your messaging must conform, and is often a consideration for interoperability with other platforms.
Difference between XmlSerializer & DataContract Serializer

XmlSerializer
DataContractSerializer
Advantages:
1. Opt-out rather than opt-in properties to serialize. This mean you don’t have to specify each and every property to serialize, only those you don’t want to serialize

2. Full control over how a property is serialized including it should be a node or an attribute
3. Supports more of the XSD standard
Disadvantages:
1. Can only serialize properties
2. Properties must be public
3. Properties must have a get and a set which can result in some awkward design
4. Supports a narrower set of types
5. Cannot understand the DataContractAttribute and will not serialize it unless there is a SerializableAttribute too
Advantages:
1. Opt-in rather than opt-out properties to serialize. This mean you specify what you want serialize
2. Because it is opt in you can serialize not only properties, but also fields.  You can even serialize non-public members such as private or protected members. And you dont need a set on a property either (however without a setter you can serialize, but not deserialize)
3. Is about 10% faster than XmlSerializer to serialize the data because since you don’t have full control over how it is serialize, there is a lot that can be done to optimize the serialization/deserialization process.
4. Can understand the SerializableAttribute and know that it needs to be serialized
5. More options and control over KnownTypes
Disadvantages:
1. No control over how the object is serialized outside of setting the name and the order

IXmlSerializable:
If we have a predefined XML schema that we need to support as a parameter or return type, we need to use IXmlSerializable types to handle mapping between the schema and our complex types.
IXmlSerializable gives us the ability to do the following:
  • Associate the XML schema with the appropriate parameter or return type. This is done by implementing the GetSchema() method of the IXmlSerializable type, or by applying the XmlSchemaProviderAttribute. The latter is best since it allows for a static method to return the schema to the runtime when the service description is being produced – rather than an instance method which requires the IXmlSerializable type to be constructed.
  • Process incoming XML when the ReadXml() method is called by the runtime and construct the appropriate complex types.
  • Write outgoing XML from the appropriate complex type instances when the WriteXml() method is called by the runtime.
A partial view of an IXmlSerializable implementation
[XmlSchemaProvider("GetSchema")]
public class LinkItemSerializer: IXmlSerializable
{
    public LinkItem LinkItem {get; set;}
    public LinkItemSerializer(LinkItem item)
    {
        this.LinkItem = item;
    }
    public static XmlQualifiedName GetSchema(XmlSchemaSet schemaSet) {…}
    #region IXmlSerializable Members
    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema(){…}
    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader){…}
    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer){…}
    #endregion
}
Message Contracts
Message is the packet of data which contains important information. WCF uses these messages to transfer information from Source to destination. WCF uses SOAP Message format for communication. Message contracts give you more control over the actual SOAP message for a service operation request or reply by providing access to the SOAP headers and bodies directly.
When you use message contracts you supply a type decorated with the MessageContractAttribute as the only parameter to a service operation and as the return type as shown below
A service contract that employs message contracts
[ServiceContract(Namespace = "urn:WCFEssentials/Samples/2008/12")]
public interface IArticlesManagerService
{
    [OperationContract]
    AddArticleLinkResponse AddArticleLink(AddArticleLinkRequest requestMessage);
    [OperationContract]
    GetArticleLinksResponse GetArticleLinks(GetArticleLinksRequest requestMessage);
}
Normally you will create request and reply message contracts, paired for each operation. By applying the MessageHeaderAttribute or the MessageBodyMemberAttribute to properties of the message contract you can create message headers and body element for serialization in a request or reply.
Message contracts are particularly useful in the following scenarios:
  • When you want to include custom message headers in the request or reply.
  • Disable message wrapping for interoperability with platforms that do not wrap messages.
  • Supply multiple body members in the reply.
Code listing below shows the request and reply message contracts from Code listing above illustrating these features.
Request and reply message contracts
[MessageContract(IsWrapped = false)]
public class GetArticleLinksRequest
{
    [MessageHeader]
    public string LicenseKey {get; set;}
}
[MessageContract(IsWrapped = false)]
public class GetArticleLinksResponse
{
    public GetArticleLinksResponse(List<LinkItem> item)
    {
        this.Items = item;
    }
    [MessageBodyMember]
    public List<LinkItem> Items {get; set;}
}
You can also control message protection (encryption and signing) of individual header and body elements although this is not a common requirement.

Can’t mix datacontracts and messagecontracts?

You cannot specify a DataContract as an input argument to an operation and have it return a MessageContract, or specify a MessageContract as the input argument to an operation and have it return a DataContract. You can mix typed and untyped messages, but not messageContracts and DataContracts. Mixing message and data contracts will cause a runtime error when you generate WSDL from the service.

Recommendations: Contracts
  1. Implement service contracts on interfaces not classes.
  2. Always provide a namespace to ServiceContractAttribute and DataContractAttribute.
  3. Provide explicit names for service contracts, service operations, data contracts and data members to avoid refactoring errors. As an alternative to this, be sure that developers know the impact of refactoring these types.
  4. Use the same namespace for service contracts and associated callback contracts.
  5. Implement only one-way calls in callback contracts.
  6. Prefer data contracts for complex type serialization and avoid POCO (attribute-free data contract) types.
  7. Apply the DataMemberAttribute to property accessors instead of fields and, at a minimum, supply explicit values for IsRequired and Order.
  8. Use CollectionDataContractAttribute to control key and item names for collection and dictionary types.
  9. Apply known types to the appropriate scope and use dynamic known types only when the application does not require versioning as new types are introduced.
  10. Use the XmlSerializer to help with ASMX migration only when it is prohibitive to reverse engineer complex types into data contracts.
  11. When using the XmlSerializer use it for the entire service contract, not for individual operations.

References: