Prerequisite
Reader of this article should have basic understanding of WCF, End points, Visual studio and bindings.
Background
In our day to day operations we come across scenarios where we have to reflect changes on client when there is some change done sever. One way is to implement polling model where client will keep on polling server to check changes but this approach is very inefficient better way is to implement a mechanism where server can push client to reflect update whenever corresponding change occurs on server. WCF provide WSDualHttpBinding or (Duplex) to achieve same very efficiently. Below I have described set by step example to explain implementation.
Introduction
In the example described below a client application is sending a request to server for registration of name. On registration, server is sending a notification to client for successful registration. To make the notification more responsive I have used timer to send notification in intervals.
This example has three components
- Service library - Server with DuplexServiceLibrary (WCF service library) which have implementation of service & service contracts.
- Service host – A console application to host the service.
- Client – A console application to act as client (consumer of service)
Implementing server
In visual studio add new project, add WCF Service library. Here VS 2012 is used but VS 2008 can also be used
Below is the service contract IDuplexService containing the method for registration. To keep simple only one method is added in it. We need to add CallbackContract attribute to define callback service interface for
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(IDuplexServiceCallback))]
public interface IDuplexService {
[OperationContract(IsOneWay = true)]
void Registration(string Name);
}
Below is the callback Interface definition which consists of NotifyRegistration method which will result in sending notification to clients. OperationContract message exchange pattern is one way (IsOneWay = true) because in this case only one message is transmitted. The receiver does not send a reply message, nor does the sender expect one.
[ServiceContract]
public interface IDuplexServiceCallback {
[OperationContract(IsOneWay = true)]
void NotifyRegistration(string Name);
}
Implement the DuplexService for Registration. Here timer is used to invoke callback method at regular interval which can be update client respectively.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class DuplexService : IDuplexService
{
#region IDuplexService Members
string result = "Your request has been regitered by Application ";
public static Timer Timer;
public static IDuplexServiceCallback Callback;
public DuplexService()
{
}
public void Registration(string Name)
{
Callback = OperationContext.Current.GetCallbackChannel<IDuplexServiceCallback>();
result = Name + " :: " + result;
Timer = new Timer(1000);
Timer.Elapsed += OnTimerElapsed;
Timer.Enabled = true;
}
void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
string notification = result + " @ " + DateTime.Now.ToString();
Callback.NotifyRegistration(notification);
}
Now we need to define end point on server. For call back service (push model) we need wsDualHttpBinding. Below is the complete app.config code for service.
="1.0"="utf-8"
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="DuplexServiceLibrary.DuplexService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8090/DuplexService/" />
</baseAddresses>
</host>
<endpoint address="" binding="wsDualHttpBinding" contract="DuplexServiceLibrary.IDuplexService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Implementing service host
Now with service ready we now have to implement service host. We can use new command line application to create a host name DuplexServiceHost. Add reference of DuplexServiceLibrary and initialize the service host
static void Main(string[] args) {
ServiceHost host = new ServiceHost(typeof(DuplexService));
ConsoleColor oldColour = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("DuplexService is up and running with the following endpoints:");
foreach (ServiceEndpoint se in host.Description.Endpoints)
Console.WriteLine(se.Address.ToString());
Console.ReadLine();
host.Open();
host.Close();
}
Now add new App.config file to this console application and copy the app.config of the DuplexService.
Implementing Client.
Add new console application (name DuplexClient ) to the solution and rename class program to client (just to have different name from service host). Now add service reference to client with namespace DuplexServiceReference
Adding service reference will add new app.config to the client with required endpoints.
="1.0"="utf-8"
<configuration>
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IDuplexService" clientBaseAddress="http://localhost:8091/" />
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8090/DuplexService/" binding="wsDualHttpBinding"
bindingConfiguration="WSDualHttpBinding_IDuplexService" contract="DuplexServiceReference.IDuplexService"
name="WSDualHttpBinding_IDuplexService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
Now implement Client. Define duplexClient for the service as below.
private static DuplexServiceReference.DuplexServiceClient duplexClient;
Define new class to implement the NotifyRegistration method of the IDuplexServiceCallback contract as shown below
public class DuplexServiceCallBackHandler : DuplexServiceReference.IDuplexServiceCallback{
public void NotifyRegistration(string Name){
ConsoleColor oldColour = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Notification : ({0})", Name);
}
}
Instantiate the context for the service in Main method.
InstanceContext context = new InstanceContext(new DuplexServiceCallBackHandler());
duplexClient = new DuplexServiceReference.DuplexServiceClient(context, "WSDualHttpBinding_IDuplexService");
Call the registration method of the service
duplexClient.Registration(name);
Console.ReadLine();
Complete implementation of Client is given below.
class Client{
private static DuplexServiceReference.DuplexServiceClient duplexClient;
static void Main(string[] args){
InstanceContext context = new InstanceContext(new DuplexServiceCallBackHandler());
duplexClient = new DuplexServiceReference.DuplexServiceClient(context, "WSDualHttpBinding_IDuplexService");
try{
Console.WriteLine("This is a client, press enter initiate request to server");
Console.ReadLine();
string name = "Sudhir";
duplexClient.Registration(name);
Console.ReadLine();
}
catch (TimeoutException timeProblem){
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
duplexClient.Abort();
Console.Read();
}
catch (CommunicationException commProblem){
Console.WriteLine("There was a communication problem. " + commProblem.Message);
duplexClient.Abort();
Console.Read();
}
}
}
public class DuplexServiceCallBackHandler : DuplexServiceReference.IDuplexServiceCallback
{
public void NotifyRegistration(string Name){
ConsoleColor oldColour = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Notification : ({0})", Name);
}
}
Now with client and server ready go to solution properties and set multiple startup projects
Now build solution and run. It will show two command prompts. One for service host which shows the service endpoint defined. Other one is client. As per logic written in client press enter to register on server with defined interval on server client will be updated with the notification. Please ensure to run Visual studio in Admin mode.
Complete solution can be downloaded to see the implementation.