Click here to Skip to main content
15,881,204 members
Articles / Programming Languages / C# 4.0

Duplex Service in WCF

Rate me:
Please Sign up or sign in to vote.
4.94/5 (15 votes)
29 Sep 2013CPOL2 min read 77.4K   27   8
Duplex service in WCF

In WCF, a service can call back to its clients. That is to say that, at the time of call back, the service behaves as a client as well as the client becomes the service, and the client must assist hosting the call back object. To support call back, the underlying transport of the binding must support bidirectional. So, for the nature of connectionless, we cannot use all bindings for the call back operation. For instance, BasicHttpBinding or WsHttpBinding does not support callback while WsDualHttpBinding supports it, because this binding establishes two HTTP channels to do that; one for client to service another for service to client. Also, NetTcpBinding and NetNamedPipeBinding supports callback since their underlying transport is bidirectional.

Callback service can be supported by using CallbackContract property in the ServiceContract attribute. Only one callback contract is allowed for a service contract. After defining a callback contract, we require to set up the client for up keeping the callback and also to offer the callback endpoint to the service for each and every call.

In the example given below, the callback contract defines the operations to which the service can call on the client endpoint.

C#
public interface INotificationServiceCallBack
{
    [OperationContract(IsOneWay = true)]
    void OnNotificationSend(string message);
}

Implementation of this Service Contract, 

C#
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class NotificationServiceCallBack : INotificationServiceCallBack
{
    public void OnNotificationSend(string message)
    {
        Console.WriteLine(message);
        Console.ReadLine();
    }
}

Here CallbackBehavior refers to how the callback of this operation will act which is similar to ServiceBehavior.

And the service contract has been defined like the way given below:

C#
[ServiceContract(CallbackContract = typeof(INotificationServiceCallBack))]
public interface INotificationServices
{
    [OperationContract]
    void SendNotification(string message);
}

To make a way around for the service to call, clients must expose an endpoint to the service. This has been done by the following way:

C#
public class Program
{
    public static INotificationServices Proxy
    {
        get
        {
            var ctx = new InstanceContext(new NotificationServiceCallBack());
            return new DuplexChannelFactory<INotificationServices>
            (ctx, "WSDualHttpBinding_INotificationServices").CreateChannel();
        }
    }
    static void Main(string[] args)
    {
        Proxy.SendNotification("Are u ready?");
        Console.ReadLine();
    }
}

Here InstanceContext is the execution scope of inner most service instance. It provides a constructor that takes the service instance to the host.

And now service implementation,

C#
public class NotificationService : INotificationServices
{
    public INotificationServiceCallBack Proxy
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel
            <INotificationServiceCallBack>();
        }
    }
    public void SendNotification(string message)
    {
        Console.WriteLine("\nClient says :" + message);
        Proxy.OnNotificationSend("Yes");
    }
}

In the above example, we see that the service has the proxy of INotificationServiceCallBack and call its operation which the clients will handle.

That’s it. Now the total code portion that I have used here has been given.

Services and Implementations

C#
public interface INotificationServiceCallBack
{
    [OperationContract(IsOneWay = true)]
    void OnNotificationSend(string message);
}
C#
[ServiceContract(CallbackContract = typeof(INotificationServiceCallBack))]
public interface INotificationServices
{
    [OperationContract]
    void SendNotification(string message);
}
C#
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class NotificationServiceCallBack : INotificationServiceCallBack
{
    public void OnNotificationSend(string message)
    {
        Console.WriteLine(message);
        Console.ReadLine();
    }
}
C#
public class NotificationService : INotificationServices
{
    public INotificationServiceCallBack Proxy
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel
            <INotificationServiceCallBack>();
        }
    }

    public void SendNotification(string message)
    {
        Console.WriteLine("\nClient says :" + message);
        Proxy.OnNotificationSend("Yes");
    }
}

Server and its Configuration

C#
class Program
{
    static void Main(string[] args)
    {
        var svcHost = new ServiceHost(typeof(NotificationService));
        svcHost.Open();
        Console.WriteLine("Available Endpoints :\n");
        svcHost.Description.Endpoints.ToList().ForEach
        (endpoint => Console.WriteLine(endpoint.Address.ToString()));
        Console.ReadLine();
        svcHost.Close();
    }
}
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="Rashim.RND.WCF.CallBack.Services.NotificationService">
        <host>
          <baseAddresses>
            <add baseAddress = "net.Tcp://localhost:8732/"/>
            <add baseAddress="http://localhost:8888"/>
          </baseAddresses>
        </host>
        <endpoint address="CallbackService" 
        binding="netTcpBinding" contract="
        Rashim.RND.WCF.CallBack.Interfaces.INotificationServices"/>
        <endpoint address="CallbackService" 
        binding="wsDualHttpBinding" contract="
        Rashim.RND.WCF.CallBack.Interfaces.INotificationServices"/>
        <endpoint address="mex" binding="
        mexTcpBinding" contract="IMetadataExchange" />
        <endpoint address="http://localhost:8888/mex" 
        binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata />
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Client and its Configuration

C#
public class Program
{
    public static INotificationServices Proxy
    {
        get
        {
            var ctx = new InstanceContext(new NotificationServiceCallBack());
            return new DuplexChannelFactory<INotificationServices>
            (ctx, "WSDualHttpBinding_INotificationServices").CreateChannel();
        }
    }
    static void Main(string[] args)
    {
        Proxy.SendNotification("Are u ready?");
        Console.ReadLine();
    }
}
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="http://localhost:8888/CallbackService" 
      binding="wsDualHttpBinding" 
      contract="Rashim.RND.WCF.CallBack.Interfaces.INotificationServices" 
      name="WSDualHttpBinding_INotificationServices">
      </endpoint>
      <endpoint address="net.tcp://localhost:8732/CallbackService" 
      binding="netTcpBinding"
 contract="Rashim.RND.WCF.CallBack.Interfaces.INotificationServices" 
 name="NetTcpBinding_INotificationServices">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration> 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer RightKnack Limited
Bangladesh Bangladesh
A big fan of getting down the latest cutting-edge technologies to the ground to innovate exceptionally amazing ideas.

My Blog: http://rashimuddin.wordpress.com/

My Email: rashimiiuc at yahoo dot com

Comments and Discussions

 
QuestionDownload Pin
Member 899391429-Jan-18 19:44
Member 899391429-Jan-18 19:44 
QuestionDynamic App.config Pin
amruthrajv17-Sep-16 19:58
amruthrajv17-Sep-16 19:58 
QuestionGood example for duplex communication Pin
UttamPrasad29-Oct-14 20:01
UttamPrasad29-Oct-14 20:01 
AnswerRe: Good example for duplex communication Pin
UttamPrasad30-Oct-14 18:55
UttamPrasad30-Oct-14 18:55 
GeneralRe: Good example for duplex communication Pin
HocusPocus1234-Mar-15 22:43
HocusPocus1234-Mar-15 22:43 
GeneralRe: Good example for duplex communication Pin
amruthrajv17-Sep-16 21:30
amruthrajv17-Sep-16 21:30 
QuestionVery nice article, can you release example with dynamic Configuration (Without app.Config)? Pin
Eladleshem777-Jul-14 2:28
Eladleshem777-Jul-14 2:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.