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.
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 |
To
know detail about this kindly read from blog of Dan Rigsby at http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/
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
- Implement service contracts on interfaces not classes.
- Always provide a namespace to ServiceContractAttribute and DataContractAttribute.
- 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.
- Use the same namespace for service contracts and associated callback contracts.
- Implement only one-way calls in callback contracts.
- Prefer data contracts for complex type serialization and avoid POCO (attribute-free data contract) types.
- Apply the DataMemberAttribute to property accessors instead of fields and, at a minimum, supply explicit values for IsRequired and Order.
- Use CollectionDataContractAttribute to control key and item names for collection and dictionary types.
- 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.
- Use the XmlSerializer to help with ASMX migration only when it is prohibitive to reverse engineer complex types into data contracts.
- When using the XmlSerializer use it for the entire service contract, not for individual operations.
References:
No comments:
Post a Comment