Enumeration in DataContract of WCF

By default Enums are serializable. If we define Enum at service side and use it in Data Contract, it is exposed at the client side.

For example, if we have an Enum as below,

clip_image001[1]

And we are using it in DataContract as below

clip_image003[1]

By default Enum is serialized.

So, let us see the default behavior of Enum with an example.

1. Create a DataContract called Product.

Product.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace WcfService1
{
    [DataContract]
    public class Product
    {
        [DataMember]
       public  string ProductName;
        [DataMember]
       public  ProductDeliveryPriority ProductPriority;
       
    }
     public  enum ProductDeliveryPriority
    {
             Low,     
        Normal,
              High,
               Urgent

    }
}

2. Create the Service Contract. We are just returning a Product from the service.

IService1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace WcfService1
{
  [ServiceContract ]
    public  interface IService1
    {

      [OperationContract]
      Product GetProduct();
    
    }
}

 

3. Implement the service in service definition .

Service1.svc.cs

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService1
{
   
    public class Service1 : IService1 
    {
        public Product GetProduct()
        {
            Product p = new Product { ProductName = "Pen", ProductPriority = ProductDeliveryPriority.Normal };
            return p;            
                       
        }  
       
    }
}

4. Define the EndPoint in config file as below. We are exposing the service with basicHttpBinding. 

Web.Config

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name ="WcfService1.Service1" >
        <endpoint address ="" binding ="basicHttpBinding" contract ="WcfService1.IService1"/>
        <endpoint address ="mex" binding ="mexHttpBinding" contract ="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress ="<a href="http://localhost:8181/Service1.svc&quot;/">http://localhost:8181/Service1.svc"/</a>>
          </baseAddresses>
        </host>
      </service>     
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
 
</configuration>

5. Test the service in browser

clip_image005[1]

6. Consume the service at the client. Add the service reference at the client side and create the proxy.

Program.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ConsoleApplication1.ServiceReference1;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
          
                Service1Client proxy = new Service1Client();
                Product p = proxy.GetProduct();
                Console.WriteLine(p.ProductName);
                Console.WriteLine(p.ProductPriority.ToString());
           
            Console.ReadKey(true);
        }
           
    }
}

We added the service reference and namespace. On running the output we will get is

clip_image007[1]

Excluding certain ENUM values

If we want to exclude certain member from ENUM then we need to follow below steps

1. Decorate the Enum with DataContract attribute

clip_image008[1]

2. Decorate the entire member we want to expose to client as EnumMember. Any Enum member not decorated with EnumMember will not be exposed to the client.

clip_image009[1]

In above Enum definition we are not decorating Normal with EnumMember . and in service we are returning Normal to the client . so when client will try to access normal enum value , it will throw an error.

So let us modify the Enum as below,

Modified Enum definition

[DataContract]
   public  enum ProductDeliveryPriority
    {
       [EnumMember]
       Low,     
        Normal,
       [EnumMember]
        High,
        [EnumMember]
        Urgent

    }

And at the client side while accessing

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ConsoleApplication1.ServiceReference1;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Service1Client proxy = new Service1Client();
                Product p = proxy.GetProduct();
                Console.WriteLine(p.ProductName);
                Console.WriteLine(p.ProductPriority.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadKey(true);
        }
           
    }
}

Output

clip_image011[1] 

We are getting this error at client side because in service we are retuning a Product with ProductPriority normal but normal is not attributed with EnumMember. So it is not exposed on wire or serialized.

Accessing WCF service without creating Proxy

Each time when we want to consume a WCF service, we need to create proxy at client side. To create proxy, service must expose metadata endpoint.

Normally

1. We create a WCF service

2. Expose metadata endpoint

3. Add service reference at client side to create the proxy.

4. Using the proxy calls the service operation contracts.

Normally we call the service as

clip_image002

Let us assume we want to call the service using channel without creating proxy or adding the service reference. We need to follow the below steps

Step 1

Put all the DataContract or ServiceContract in a separate DLL or class library. Add the reference of System.ServiceModel in class library. And create the service contract as below,

MyServiceContract.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace ContractDll
{
  [ServiceContract]
    public  interface MyServiceContract
    {

      [OperationContract]
      string GetData(int value);

    }
}

Assume we have created a service library called ContractDLL

Step 2

Create a WCF Service application and implement the service contract created in step 1. For that add the reference of project created in step 1 in WCF service application.

Service1.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ContractDll;

namespace WcfService1
{
   
    public class Service1 : MyServiceContract
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

       
    }
}

Add the EndPoint in config file.

clip_image004

In above config file

1. ContractDLL.MyServiceContract is name of the service contract exposed.

2. There is no metadata exchange endpoint in the config file.

Full Web.Config is as below,

Web.Config

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name ="WcfService1.Service1" >
        <endpoint address ="" binding ="basicHttpBinding" contract ="ContractDll.MyServiceContract"/>      
        <host>
          <baseAddresses>
            <add baseAddress ="<a href="http://localhost:8181/Service1.svc&quot;/">http://localhost:8181/Service1.svc"/</a>>
          </baseAddresses>
        </host>
      </service>     
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
 
</configuration>

Step 3

Create the client. We are creating a console client to consume the service with channel or without creating proxy. So follow the below steps

1. Do not add the service reference.

2. Add the reference of System.ServiceModel.

3. Add the reference of class library created in step1.

Now we need to

1. Create a ChannelFactory

clip_image005

2. Create a binding of the type exposed by service

clip_image007

3. Create EndPoint address

clip_image009

4. Pass Binding and EndPoint address to ChannelFactory

clip_image011

5. Now create the channel as below ,

clip_image013

6. Call the service method on this channel as below ,

clip_image015

So full code of client will be like below

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ContractDll;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ChannelFactory<MyServiceContract> factory = null;
            try
            {              

                BasicHttpBinding binding = new BasicHttpBinding();
                EndpointAddress address = new EndpointAddress("<a href="http://localhost:4684/Service1.svc">http://localhost:4684/Service1.svc</a>");
                factory = new ChannelFactory<MyServiceContract>(binding, address);
                MyServiceContract channel = factory.CreateChannel();
                string resturnmessage = channel.GetData(9);
                Console.WriteLine(resturnmessage);
                Console.ReadKey(true);
            }
            catch (CommunicationException)
            {
                if (factory != null)
                    factory.Abort();

            }
            catch (TimeoutException)
            {
                if (factory != null)
                    factory.Abort();
            }
            catch (Exception ex)
            {
                if (factory != null)
                    factory.Abort();
                Console.WriteLine(ex.Message);
            }
            Console.WriteLine("Proxy closed");
            Console.ReadKey(true);
        }
    }
}

And we will get output as

clip_image017

Finding Odd numbers from a Range of Number using LINQ in C#

If we have a range of number from 1 to 20 and we want to find odd among them using LINQ .

We have three options for that

1. Calling a Predicate

2. Anonymous Method

3. Lambda

clip_image002

So here we can see that we need to pass a predicate to evaluate the condition.

Calling a Predicate

Function we will pass as predicate is as below

clip_image004

We will pass this function as predicate to find odd numbers from the range of numbers.

clip_image006

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication25
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = from r in 
                         Enumerable.Range(1, 20).Where(GetOdd)
                         select r;
            foreach (var r in result)
                Console.WriteLine(r);
            Console.ReadKey(true);
        }
        static bool GetOdd(int number)
        {
            if (number % 2 != 0)
                return true;
            else
                return false; 
        }
    }
}

Output

clip_image008

Using Anonymous Method

We can use anonymous method also

clip_image010

Anonymous method is taking an input parameter and returning a Boolean value.

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication25
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = from r in
                             Enumerable.Range(1, 20).Where(delegate(int number)
                                                             { 
                                                                 if (number % 2 != 0)
                                                                     return true;
                                                                     return false; })
                                                               select r;
            foreach (var r in result)
                Console.WriteLine(r);
            Console.ReadKey(true);
        }
}
}

Output

clip_image011

Using Lambda

To make our query more readable in version 3.0 and onwards we can use Lambda instead of anonymous method also.

clip_image013

Lambda is very simple returning true when reminder is 0.

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication25
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = from r in
                             Enumerable.Range(1, 20).Where(num =>num%2!=0)
                                                               select r;
            foreach (var r in result)
                Console.WriteLine(r);
            Console.ReadKey(true);
        }
}
}

Output

clip_image015

Versioning in WCF Data Contract Part #2: Missing Members

Part #1 of the article can be read here

If we have a DataContract

Product.cs

[DataContract]
    public class Product
    {
        [DataMember(Order = 1)]
        public string ProductNumber;
        [DataMember(Order = 2)]
        public string ProductName;
        [DataMember(Order = 3)]
        public string ProductPrice;
        [DataMember(Order = 4)]
        public string ProductColor; 

    }

ServiceContract is as below

IService1.cs

namespace WcfService10
{
    
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Product  GetaProduct(Product p ); 

        
    }
}

And Service implementation is as below,

Service1.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService10
{   
    public class Service1 : IService1
    {
      public Product GetaProduct(Product p)
        {
            Product p1 = new Product
            {
                ProductNumber = p.ProductNumber,
                ProductName = p.ProductName,
                ProductPrice = p.ProductPrice,
                ProductColor = p.ProductColor
            };
          return p1; 
        }
    }
}


Now we have a service.

Now at the client side (Say it as client1) we are calling the service as below

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication1.ServiceReference1; 

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            using (Service1Client proxy = new Service1Client())
            {
                Product p = new Product{ProductNumber="1",
                                        ProductPrice="100",
                                        ProductName ="Bat",
                                        ProductColor ="White"};
            
                              
                var res = proxy.GetaProduct(p);
                Console.WriteLine(res.ProductName+"\n" + res.ProductPrice+"\n" + res.ProductNumber+"\n"+res.ProductColor);
            }
            Console.ReadKey(true);
        }
    }
}

Output

clip_image002

Now let us go ahead and modify the service implementation as below,

Service1.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService10
{   
    public class Service1 : IService1
    {
      public Product GetaProduct(Product p)
        {
            Product p1 = new Product
            {
                ProductNumber = p.ProductNumber??"Missing Number",
                ProductName = p.ProductName??"Missing Name",
                ProductPrice = p.ProductPrice??"Missing Price",
                ProductColor = p.ProductColor??"Missing color"
            };
          return p1; 
        }
    }
}

If you see the above implementation , we are assigning some default value when value of the property is not provided or in other words Members are missing.

clip_image004

So if at the client side DataContract, some DataMember is missing. In this case at the client side member ProductColor is missing

clip_image005

Now at the service side one DataMember is missing so Service implementation will return default value for that

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication1.ServiceReference1; 

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            using (Service1Client proxy = new Service1Client())
            {
                Product p = new Product{ProductNumber="1",
                                        ProductPrice="100",
                                        ProductName ="Bat"};
                                        
            
                              
                var res = proxy.GetaProduct(p);
                Console.WriteLine(res.ProductName+"\n" + res.ProductPrice+"\n" + res.ProductNumber+"\n"+res.ProductColor);
            }
            Console.ReadKey(true);
        }
    }
}

Output

clip_image007

OnDeserializing event

In case of missing DataMember , we can use OnDeserializing event to share the logic across all the party

Product.cs

[DataContract]
    public class Product
    {
        [DataMember(Order = 1)]
        public string ProductNumber;
        [DataMember(Order = 2)]
        public string ProductName;
        [DataMember(Order = 3)]
        public string ProductPrice;
        [DataMember(Order = 4)]
        public string ProductColor;
        [OnDeserializing]
        void OnDeserializing(StreamingContext context)
        {
            ProductName = "Name Missing";
            ProductNumber = "Number Missing";
            ProductColor = "Color Missing ";
            ProductPrice = "Price Missing";
        }

    }   

Versioning in WCF Data Contract Part #1: Adding New Members

DataContract versioning requires when some modification has been done to the existing DataContract exposed to the client from the service or vice versa. If either service or client is changing the schema of DataContract exposed then new version of DataContract come into action and both party involved in communication should be able to accommodate the changes done in the DataContract.

The scenario causes for new version of DataContract is as below,

1. Missing a member from existing DataContract .

2. Adding a new member to existing DataContract.

3. Round Tripping

In this article we will explore New Member scenarios

Adding a New Member to existing DataContract

This is most common changes we do to give new version to DataContract.

For example we have a DataContract through which we are exposing Product custom class to the client

Product.cs

[DataContract]
    public class Product
    {
        [DataMember(Order = 1)]
        public string ProductNumber;
        [DataMember(Order = 2)]
        public string ProductName;
        [DataMember(Order = 3)]
        public string ProductPrice;

    }

And we have ServiceContract which is returning a Product from the service

IService1.cs

namespace WcfService10
{

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Product GetaProduct();

    }
}
}

Service implementation is as below,

Service1.svc.cs

namespace WcfService10
{

    public class Service1 : IService1
    {
        public Product GetaProduct()
        {
            try
            {
                Product p = new Product { ProductName = "Pen", ProductPrice = "9", ProductNumber = "1" };
                return p;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

    }
}

Now at the client side, we can call the service as below. (Call this client as Client1 )

Program.cs

using ConsoleApplication1.ServiceReference1;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            using (Service1Client proxy = new Service1Client())
            {
                var res = proxy.GetaProduct();
                Console.WriteLine(res.ProductName + res.ProductPrice + res.ProductNumber);
            }
            Console.ReadKey(true);
        }
    }
}

Output

clip_image002

Now let us go ahead and modify the DataContract at the service. Just add one more parameter

clip_image003

So now DataContract will look like

Product.cs

[DataContract]
    public class Product
    {
        [DataMember(Order = 1)]
        public string ProductNumber;
        [DataMember(Order = 2)]
        public string ProductName;
        [DataMember(Order = 3)]
        public string ProductPrice;
        [DataMember(Order = 4)]
        public string ProductColor;

    }

And now go ahead and modify the service implementation as below,

Service1.svc.cs

namespace WcfService10
{

    public class Service1 : IService1
    {
        public Product GetaProduct()
        {
            try
            {
                Product p = new Product { ProductName = "Pen", ProductPrice = "9", ProductNumber = "1",ProductColor="Red" };
                return p;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

    }
}

Now do not update the service reference at the clien1. What I mean here is that same version of DataContract at the client 1. And create one more client and call it as client 2. Use updated service at the client.

So, now client 1 will look like exactly it was previously

Program.cs (Client1)

using ConsoleApplication1.ServiceReference1;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            using (Service1Client proxy = new Service1Client())
            {
                var res = proxy.GetaProduct();
                Console.WriteLine(res.ProductName + res.ProductPrice + res.ProductNumber);
            }
            Console.ReadKey(true);
        }
    }
}

Output would be exactly the same as it was with previous version of DataContract

clip_image005

And new created client (Client2) will look like below,

Program.cs(Client2)

using ConsoleApplication2.ServiceReference1;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            using (Service1Client proxy = new Service1Client())
            {
                var res = proxy.GetaProduct();
                Console.WriteLine(res.ProductName + res.ProductPrice + res.ProductNumber+res.ProductColor);
            }
            Console.ReadKey(true);
        }
    }
}

This client is using version2 of DataContract and output would contain newly added member in DataContract.

clip_image007

So on deseralization new added DataMember will be ingnored by DataContractSeralizer and both party will continue working without any breakage.

clip_image009

Serialization order in Data Contract

If you have a Data Contract in your WCF service as below,

Student.cs


    [DataContract]
    public class Student
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Address { get; set; }
        [DataMember]
        public string RollNumber { get; set; }
    }

On serialization properties of data contract will get serialized in alphabetical order. So at the client side serialized data contract will look like clip_image002 So we can see in serialized data contract at the client side properties are serialized in alphabetical order. Now if you want to manage the order of serialization, you need to use Order attribute of DataMember. Student.cs



    [DataContract]
    public class Student
    {
        [DataMember(Order=3)]
        public string Name { get; set; }
        [DataMember(Order=2)]
        public string Address { get; set; }
        [DataMember(Order=1)]
        public string RollNumber { get; set; }
    }

}

On serialization properties of data contract will get serialized in order specified at order attribute of data contract.

clip_image004

Note: To see the order of serialization click on ServiceReference1 in object explorer when you are adding that at the client side. You will get a class Student.cs

Two important points

1. If two properties are having same order then they will get serialized in alphabetical order.

2. In inheritance also DataContract will be serialized in alphabetical order , if explicitly order is not specified on DataMember.

Using Lambda expression in FindAll()

I got a critical comment from @amazedsaint. You can read his blog http://amazedsaint.blogspot.com/

If you read my previous post http://dhananjaykumar.net/2010/10/01/findall-finding-multiple-items-in-c-list/ ,

I am using a method GreaterThanHun As predicate to pass as parameter to FindAll()

Instead of that we can use

1. Anonymous method

2. Lambda expression

So, I am going to show you here how we could use Lambda expression

clip_image002

So here we are just writing a lambda instead of calling a function.

Program.cs

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication24
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> lst = new List<int>();
            lst.Add(20);
            lst.Add(300);
            lst.Add(400);
            lst.Add(9);
            lst.Add(19);
            lst.Add(789);
            lst.Add(45);
            List<int> lstgrthund = lst.FindAll(a=>a>100? true:false);
            foreach (var r in lstgrthund)
            {
                Console.WriteLine(r);
            }
            Console.ReadKey(true);
        }

Output

clip_image004