Callback Reentrancy or returning values in callback or duplex service

PART#1 of this article is here

Objective:

This article will explain how to return values in call back or duplex operation.

Before reading this article, I strongly recommend to read my first article post on this series. This article is fully based on the A Simple Duplex Service in WCF.

If you read above article, you will notice below points

1. The entire operation contract is configured for one way operation.

2. Return type of the entire operation contract is void.

Now assume there is a requirement

1. To have request and reply on operation contract.

2. To return some value from functions rather than void.

I mean we want signature of call back operation contract and operation of service contract as below ,

clip_image001

clip_image002

Now if we modify contract as below,

IService1.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 WcfService3
{
    [ServiceContract(CallbackContract=typeof(IMyContractCallBack))]
    public interface IService1
    {
        [OperationContract]
        string  NormalFunction();
    }
    public interface IMyContractCallBack
    {
        [OperationContract]
        string  CallBackFunction(string str);

    }
}

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 WcfService3
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
    public class Service1 : IService1
    {
        public string  NormalFunction()
        {
            IMyContractCallBack callback = OperationContext.Current.GetCallbackChannel<IMyContractCallBack>();
           return  callback.CallBackFunction("Calling from Call Back");

        }

    }
}

And service is configured as below,

Web.Config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name ="svcbh">         
          <serviceMetadata httpGetEnabled="False"/>         
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <!--<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />-->
    <services>
      <service name ="WcfService3.Service1" behaviorConfiguration ="svcbh" >
        <host>
          <baseAddresses>
            <add baseAddress = "http//localhost:9000/Service1/" />
          </baseAddresses>
        </host>
        <endpoint name ="duplexendpoint" 
                  address ="" 
                  binding ="wsDualHttpBinding" 
                  contract ="WcfService3.IService1"/>
        <endpoint name ="MetaDataTcpEndpoint"
                  address="mex" 
                  binding="mexHttpBinding" 
                  contract="IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer
</configuration>

Once we consume the above service in a console application and modify the duplex proxy class as below,

MyCallBack.cs

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

namespace ConsoleApplication1
{
    class MyCallBack :IService1Callback ,IDisposable

    {
        Service1Client proxy;

        public string   CallBackFunction(string str)
        {
            return str;
        }

        public void callService()
        {
           InstanceContext context = new InstanceContext(this);
           proxy = new Service1Client(context);
          Console.WriteLine(proxy.NormalFunction());

        }

        public void Dispose()
        {
            proxy.Close();
        }
    }
}

And at the client side,

Programs.cs

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

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

            MyCallBack obj = new MyCallBack();
            obj.callService();
            Console.Read();
            obj.Dispose();

        }
    }
}

And after consumption of service try to run the client, you will get an exception while trying to call the operation contract from call back function.

clip_image004

The error message is operation would deadlock because the reply cannot be received until the current message completes processing.

clip_image005

So how to solve the above exception?

We will have to configure the service behavior for reentrancy.

clip_image007

By setting the concurrency mode as Reentrant

1. Service will access the operation context and call back reference and then invokes it.

2. After the call back returns control will go to service and the lock will get reallocated to thread.

So now modified Service implementation will be 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 WcfService3
{
    [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
    public class Service1 : IService1
    {
        public string  NormalFunction()
        {
            IMyContractCallBack callback = OperationContext.Current.GetCallbackChannel<IMyContractCallBack>();
           return  callback.CallBackFunction("Calling from Call Back");

        }

    }
}

Now on running the client after service consumption, we will get output as below,

clip_image009

A Simple Duplex Service in WCF

Objective

This article will give step by step explanation on how to create a simple duplex service in WCF.

In call back operation or duplex service, Service can also call some function at the client .

clip_image002

1. Duplex service allows calling back some operation (function) on the client.

2. Duplex service also knows as Call Backs.

3. All Binding does not support duplex service.

4. Duplex communication is not standard. They are absolute Microsoft feature.

5. wsDualHttpBinding supports duplex communication over HTTP binding.

6. Duplex communication is possible over netTcpBinding and netNamedPipeBinding

Steps involved in creating a duplex service

1. Create a WCF Service

2. Create a call back contract.

3. Create service contract

4. Implement service and configure the behavior for duplex communication and call the client function at the service.

5. Configure the endpoint for duplex service

6. Create the client.

7. Call the WCF Service

Create a WCF Service

1. Open visual studio and create a new project. Select WCF Service application from WCF project template tab.

2. Delete all the default generated code.

3. If using VS2010, open web.config and comment serviceHostEnvironment as below.

clip_image004

4. If using VS2008 then delete the default End Point generated.

5. Now you are left with empty IService1 and Service1.svc.cs file.

Create a call back contract

1. Open IService1.cs .

2. Add an interface in the same file. Give any name of the interface. I am giving name here IMyContractCallBack

clip_image005

3. Create an operation contract in the Interface.

4. Make sure return type is Void.

5. Make sure IsOneWayProperty is set to true.

6. There is no need to mark call back interface as ServiceContract.

Explanation

At the client side, this call back interface will get implemented and on a duplex channel Service will call the CallBackFunction from the client.

Create service contract

1. Open IService1.

2. Declare operation contract called from the client. Make the isoneway to property to true from the service operation contract also.

clip_image006

3. Set the CallBackContract in Service contract attribute. Set the call back contract as the interface created for the call back.

clip_image008

Here IMyContractCallBack is name of the interface user for duplex communication.

So Service contract and call back contract will be as below,

IService1.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 WcfService3
{
    [ServiceContract(CallbackContract=typeof(IMyContractCallBack))]
    public interface IService1
    {
        [OperationContract(IsOneWay=true)]
        void NormalFunction();
    }
    public interface IMyContractCallBack
    {
        [OperationContract(IsOneWay=true)]
        void CallBackFunction(string str);
    }
}

Implement service and configure for duplex communication and call client function 1. In service behavior set the instance mode of the service to percall. clip_image010

2. Create a call back channel

clip_image012

Here I am using OperationConetxt to get current call back channel. 3. Now instance of IMyContractCallBack can be used to make call at the function in call back interface contract at the client side. Like below ,

clip_image013

Here we are going to call function at the client side from the operation contract of the service.

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 WcfService3
{
    [ServiceBehavior(InstanceContextMode= InstanceContextMode.PerCall)]
    public class Service1 : IService1
    {
        public void     NormalFunction()
        {
            IMyContractCallBack callback = OperationContext.Current.GetCallbackChannel<IMyContractCallBack>();
            callback.CallBackFunction("Calling from Call Back");
        }
    }
}

Configure the endpoint for duplex service

As we discussed earlier that duplex service is not supported by all type of bindings. So while configuring the end point for the service we need to choose the binding supports duplex communication. Here we are going to use wsDualHttpBinding

1. Declare the end point with wsDualHttpBinding.

clip_image015

2. Declare the Meta data exchange end point.

clip_image016

3. Declare the host address

clip_image018

4. Declare the service behavior

clip_image020

So the service in configuration will look like

clip_image022

Web.Config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name ="svcbh">         
          <serviceMetadata httpGetEnabled="False"/>         
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <!--<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />-->
    <services>
      <service name ="WcfService3.Service1" behaviorConfiguration ="svcbh" >
        <host>
          <baseAddresses>
            <add baseAddress = "http//localhost:9000/Service1/" />
          </baseAddresses>
        </host>
        <endpoint name ="duplexendpoint" 
                  address ="" 
                  binding ="wsDualHttpBinding" 
                  contract ="WcfService3.IService1"/>
        <endpoint name ="MetaDataTcpEndpoint"
                  address="mex" 
                  binding="mexHttpBinding" 
                  contract="IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer
</configuration>

Create the client

1. Create a console application to consume this service.

2. Add the reference of System.ServiceModel. In console application project.

3. Add the service reference of the service, we created in previous steps.

Create a duplex proxy class to implement call back contract

1. Right click and add a class in console application. Give any name; I am giving the name MyCallBack.

2. Add the namespace

clip_image024

3. Implement call back contract. In our case it is IService1Callback and IDisposable.

clip_image025

Note: Since name of the service contract is IService1, so the call back interface name will be IService1Callback . It is name of service contract suffixes by keyword CallBack.

4. Now implement the call back contract method in this class.

clip_image026

5. Now make a function in this class to create duplex proxy.

a. Create an instance of InstanceContext and pass the reference of current class in the constructor of that.

clip_image027

b. Pass this context as parameter of service1client

clip_image028

c. Call the service on this proxy

clip_image029

So, the function will be

clip_image030

For your reference MyCallback class will be as below,

MyCallback.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication1.ServiceReference1;
using System.ServiceModel;
namespace ConsoleApplication1
{
    class MyCallBack :IService1Callback ,IDisposable
    {
        Service1Client proxy;
        public void   CallBackFunction(string str)
        {
            Console.WriteLine(str);
        }
        public void callService()
        {
           InstanceContext context = new InstanceContext(this);
           proxy = new Service1Client(context);
           proxy.NormalFunction();
        }
        public void Dispose()
        {
            proxy.Close();
        }
    }
}

Call the WCF Service

Create the instance of MyCallBack class and call the callService() method to call the service.

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication1.ServiceReference1;
using System.ServiceModel;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyCallBack obj = new MyCallBack();
            obj.callService();
            Console.Read();
            obj.Dispose();
        }
    }
}

Output

clip_image032

Anonymous types in C# 3.0

1. Anonymous types are new feature being added in C# 3.0.

2. These are data types being generated on the fly at the run time.

3. These data types are generated through complier rather than explicit class definition.

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
 
            var MyAnonClass = new
            {
                Name = "Scott",
                Subject = "ASP.Net"
 
            };
 
 
            Console.WriteLine(MyAnonClass.Name);
            Console.Read();
 
 
        }
    }
}
 

Output

clip_image002

A class without name is being generated and assigned to implicitly type local variable

How it works internally?

1. For an anonymous type syntax compiler generates a class.

2. Properties of the complier generated class are value and data type given in declaration.

3. Intellisense supports anonymous type class properties.

clip_image003

4. Properties of one anonymous type can be used in declaration of another anonymous type.

clip_image004

Program.cs


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

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

            var MyAnonClass = new
            {
                Name = "Scott",
                Subject = "ASP.Net"

            };


            Console.WriteLine(MyAnonClass.Name);
            Console.Read();

            var SecondAnoynClass = new
            {
                info = MyAnonClass.Name + MyAnonClass.Subject
            };

            Console.WriteLine(SecondAnoynClass.info);
            Console.Read();
            Console.Read();
        }
    }
}


Output

clip_image006

Collection initializer in C# 3.0

1. Collection initializer is new feature of C# 3.0

2. Collection initializer gives a simple syntax to create instance of a collection.

3. Any object that is implementing System.Collections.Generic.ICollection<T> can be initialized with collection initializer.

Let us say, we have a class

Student.cs


public  class Student
    {
       public string FirstName { get; set; }
       public string LastName { get; set; }
    }

Now if we want to make collection of this class and add items of type student in that collection and retrieve through the collection, we need to write below code

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication16
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> lstStudent = new List<Student>();
            Student std = new Student();
            std.FirstName = "Dhananjay";
            std.LastName = "Kumar ";
            lstStudent.Add(std);
            std = new Student();
            std.FirstName = "Mritunjay ";
            std.LastName = "Kumar";
            lstStudent.Add(std);
            foreach (Student resstd in lstStudent)
            {
                Console.WriteLine(resstd.FirstName);
            }
            Console.Read();
        }
    }

Output

clip_image002

In above code,

1. An instance of List of Student is getting created.

2. An instance of the Student is getting created.

3. Using the Add method on the list, instance of being added to list of students.

4. Using For each statement iterating through the list to get the values. Now, if instance of Student class can be assigned to List of student at the time of creation of instance of list then we call it automatic collection initializer.

clip_image004

If we see the above syntax

1. It is highly readable.

2. It is single statement.

3. Instance of Student class is getting added on the fly. And we can retrieve the values as below,

clip_image005

In retrieving implicit type local variable is being used to fetch the different instance of the student in list of student

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication16
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> lstStudent = new List<Student>()
                                         {
                                             new Student{FirstName ="Dhananjay" ,LastName="Kumar"},
                                             new Student {FirstName ="Mritunjay", LastName ="Kumar"}
                                         };
            foreach (var r in lstStudent)
            {
                Console.WriteLine(r.FirstName);
            }
            Console.Read();
        }
    }

Output

clip_image007

How it internally works?

A collection initializer invokes the ICollection<T>.Add(T) method for each specified element in order. In the above example , it will call

ICollection<Student>.Add(instance of Student )