Thursday, 28 May 2015

Method Overloading in WCF

Method Overloading in WCF

Method overloading is the process of implementing Polymorphism in Object-Oriented Programming. A method can be overloaded on the basis of type of parameters, number of parameters, and an order of parameters.
As we know, WCF code is always coded on OOP's based programming language so that it does support method overloading.

Service Interface

  [ServiceContract]

public interface ITest
{
    [OperationContract]
    string TestMethod(int para1,int para2);
    //Initail method
    [OperationContract]
    string TestMethod(string para1, string para2);
    //Overloading on the basis of type of parameters.
    [OperationContract]
    string TestMethod(int para1, string para2);
    //Overloading on the basis of  an order of parameters.
    [OperationContract]
    string TestMethod(int para1, string para2,double para3);
    //Overloading on the basis of the numbers of parameters
}

Service implementation

public class Test : ITest
{
 
    public string TestMethod(int para1, int para2)
    {
        return "TestMethod1";
    }
 
    public string TestMethod(string para1, string para2)
    {
        return "TestMethod2";
    }
 
    public string TestMethod(int para1, string para2)
    {
        return "TestMethod3";
    }
 
    public string TestMethod(int para1, string para2, double para3)
    {
        return "TestMethod4";
    }
}

Issues of method overloading in WCF

Once test the above code on WCF test client, it will throw an error contract mismatch because of the WSDL that does n't allow to create duplicate methods for clients.
Error: Cannot obtain Metadata from http://localhost:61489/Test.svc If this is a Windows (R) Communication Foundation 
service to which you have access, please check that you have enabled metadata publishing at the specified address. 
For help enabling metadata publishing, 
please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata
 
Exchange Error    URI: http://localhost:61489/Test.svc    Metadata contains a reference that cannot 
be resolved: 'http://localhost:61489/Test.svc'.    The server did not provide a meaningful reply; this might 
be caused by a contract mismatch, a premature session shutdown or an internal server error.
 
HTTP GET Error    URI: http://localhost:61489/Test.svc    There was an error downloading 
'http://localhost:61489/Test.svc'.    The request failed with the error message:--<html>
<head>        <title>The type 'MethOverWCF.Test', provided as the Service attribute
value in the ServiceHost directive, or provided in the configuration element 
system.serviceModel/serviceHostingEnvironment/serviceActivations could not be found

Solution of method overloading issue in WCF

By adding unique operationcontract behavior, we can be achieved method overloading in WCF.OperationContract has the Name property that exposes the WCF methods to WSDL Schemas.
Hide   Copy Code
[ServiceContract]
public interface ITest
{
    [OperationContract(Name="Method1")]
    string TestMethod(int para1,int para2);
    //Initail method
    [OperationContract(Name = "Method2")]
    string TestMethod(string para1, string para2);
    //Overloading on the basis of type of parameters.
    [OperationContract(Name = "Method3")]
    string TestMethod(int para1, string para2);
    //Overloading on the basis of  an order of parameters.
    [OperationContract(Name = "Method4")]
    string TestMethod(int para1, string para2,double para3);
    //Overloading on the basis of the numbers of parameters
}

Creating Client and Consuming overloaded WCF service methods

In WCF client, all service methods are called by exact same name as define in the OperationContract but method overloaded methods are called by their attribute name. In the given sample code has four different attributes (Method1, Method2, Method3, and Method4) which are exposed by overloaded TestMethod of WCF.
Hide   Copy Code
using WCFConsoleClentApp.MyTest;
namespace WCFConsoleClentApp
{
    class Program
    {
        static void Main(string[] args)
        {
            TestClient client = new TestClient();
            string callMethod1 = client.Method1(1, 1);
            string callMethod2 = client.Method2("Test", "Test");
            string callMethod3 = client.Method3(1, "Test");
            string callMethod4 = client.Method4(1, "Test", 3.5);
        }
    }
}


DataMember Attributes of WCF Data Contract

Using this article you will know what are the data member attributes and enum member attributes can be used for effective data contract design.
[DataMember] attribute needs to be marked for every fields, methods or properties of [DataContract] to make it serializable by DataContractSerializer for service request and response. DataMember properties cannot be read only or write only, it must include getter and setter. DataMember is included in System.Runtime.Serilization assembly. DataMember is a sealed class.

DataMember has below attributes.
1.  

EmitDefaultValue
DataMember EmitDefaultValue is Boolean attribute with default value of true. If the value is not provided for DataMember then the corresponding default value will be set to the member for example integer it will be set as 0, for bool it is false, any reference type it is null. If you do not want to use the default value to set then mark this attribute to false. Marking this as false will help you for reducing request response size and better interoperability.
[DataContract]
public class Order
{
    // This will be written as <OrderQty>1</OrderQty>
    [DataMember]
    public int OrderQty = 1;

    //This member not be deserialize
    //as it is EmitDefaultValue = false.
    [DataMember(EmitDefaultValue = false)]
    public double OrderTotal = 0.0;

    [DataMember(EmitDefaultValue = false)]
    public string CustomerName = string.Empty;
}
           


2.  IsRequired
DataMember IsRequired is Boolean attribute with default value of false. If the value for DataMember is required then set it to true else mark it as false. If IsRequired is marked as true with EmitDefaultValue as true and value is not provided while serialization then the default value will be emitted. If IsRequired is marked as true with EmitDefaultValue as false and value is not provided while serialization then SerializationException will be thrown.
[DataContract]
public class Order
{
    // This will be written as <OrderQty>1</OrderQty>
    [DataMember(IsRequired = false)]
    public int OrderQty = 1;
}       
           
Changing this attribute from false to true will be a breaking change to existing client communications however changing it from false to true will not break.


3.  Name
DataMember Name is string attribute with default value as name of method to which it is applied. The DataMember name property is helpful to handle some of the DataContract version issues. Some data contract changes will break the existing client communication like changing DataMember name, changing DataContract name or namespace, changing the order of DataMembers. In following example the change to Name DataMember will not be breaking change to existing client communication.
// Version 1 of DataContract Order
[DataContract]
public class Order
{
    [DataMember]
    private string OrderID;  

    [DataMember]
    private string Name;  
}

// Version 2 of DataContract Order
[DataContract]
public class Order
{
    [DataMember]
    private string OrderID;  

    [DataMember(Name = "Name")]
    private string CustomerName;  
}
           
The addition or deletion of DataMember with IsRequired = false and EmitDefaultValue = true will not break any existing clients. 

Setting the Name property will also be helpful when you are having inheritance for DataContract with same DataMember name.


4.  Order
DataMember Order attribute is of type integer. Sometime DataContract should serialized or deserialized in specific order of DataMembers. By default DataMembers are serialized or deserialized in below order.
o    1. If DataContract has derived from base DataContract so the DataMembers from base class will process first in alphabetical order.
o    2. DataMembers with no Order property set will process in alphabetical order.
o    3. Remaining DataMembers will be processed in ascending order of Order property value.
Enumeration Types in Data Contracts
·         EnumMemberAttribute allows you to create new Enumeration for DataContract. For marking the enum member use [EnumMember] to members. All the members which are required in serialization and deserialization must mark as [EnumMember].
·         Following is an example of how to use enum in DataContract. Setting value for Status DataMember to Completed will result in SerializationException as it is not marked with [EnumMember].
[DataContract]
public class Order
{
    [DataMember]
    public int OrderID;

    [DataMember]
    public Status OrderStatus;
}

[DataContract(Name = "Status")]
public enum Status
{
    [EnumMember]
    Created,

    [EnumMember]
    Shipped,

    [EnumMember]
    Delivered,

    Completed
}
   
EnumMemberAttribute has below attributes.
1.  Value
EnumMember value is string property with default value of the name of enum member to which it is applied. In above example setting DataMember Status = Delivered will result below xml. 
<Status>Delivered</Status>
 

Setting the value to enum member will replace the actual text.
[DataContract(Name = "Status")]
public enum Status
{
    [EnumMember(Value="1")]
    Created,

    [EnumMember(Value="2")]
    Shipped,

    [EnumMember(Value="3")]
    Delivered
}
            
With above Enum set DataMember Status = Delivered will result below xml. 
<Status>3</Status>