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.

About these ads

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