Monthly Archives: May 2013

WCF Duplex

In many cases a client calls a service and waits for the service call to complete forming a “one way” communication channel from the client to the service. But what if you wanted a two way communication channel, for example the client calls a service method and the service then calls methods on all connected clients. This two way pattern is known as duplex.

Create the service

Let’s create a very simple duplex service which will send messages to the connected clients when changes occur on the service.

1. Create a new console project
2. Add a new item, select WCF Service and name it whatever you want (mine’s called MyService)
3. In the Program.cs Main method type the following

ServiceHost serviceHost = new ServiceHost(typeof(MyService));
serviceHost.Open();
Console.WriteLine("Service started, press any key to quit");
Console.ReadKey();
serviceHost.Close();

4. Add a new interface named IMyCallback

public interface IMyCallback
{
   [OperationContract(IsOneWay = true)]
   void Tick(DateTime dateTime);
}

5. On the IMyService contract alter the ServiceContract to read

[ServiceContract(CallbackContract = typeof(IMyCallback))]

6. Rename the default method DoWork() to Register(), in both the interface and implementation.
7. Change the Register implementation to the following

private readonly List<IMyCallback> callbacks = new List<IMyCallback>();

public void Register()
{
   callbacks.Add(OperationContext.Current.GetCallbackChannel<IMyCallback>());
}

8. For this demo we’re going to simply call the connected client(s) periodically so add the following to MyService

private readonly Timer timer;

public MyService()
{
   timer = new Timer(TimerCallback);
   timer.Change(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
}

private void TimerCallback(object o)
{
   foreach (IMyCallback callback in callbacks)
   {
      callback.Tick(DateTime.Now);
   }
}

9. Finally edit the app.config. We’re going to use the TCP binding so set the httpGetEnabled to false, change the service binding to netTcpBinding and the mex binding to mexTcpBinding and alter the baseAddress to use the net.tcp protocol (see below)

<system.serviceModel>
   <behaviors>
      <serviceBehaviors>
         <behavior name="">
            <serviceMetadata httpGetEnabled="false" />
            <serviceDebug includeExceptionDetailInFaults="false" />
         </behavior>
      </serviceBehaviors>
   </behaviors>
   <services>
      <service name="DuplexService.MyService">
         <endpoint address="" binding="netTcpBinding" bindingConfiguration=""
                    contract="DuplexService.IMyService">
            <identity>
               <dns value="localhost" />
            </identity>
         </endpoint>
         <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
                    contract="IMetadataExchange" />
            <host>
               <baseAddresses>
                  <add baseAddress="net.tcp://localhost:8732/MyService/" />
               </baseAddresses>
            </host>
        </service>
    </services>
</system.serviceModel>

Create the client

1. Create a new console application
2. Right mouse click on References and choose Add Service Reference
3. Enter t baseAddress from the server (i.e. net.tcp://localhost:8732/MyService) then press Go
4. Set the namespace to MyService and press OK
5. We now need to implement the callback interface

public class ClientCallback : IMyServiceCallback
{
   public void Tick(DateTime dateTime)
   {
      Console.WriteLine(dateTime);
   }
}

6. And finally add the code to connect to the service

InstanceContext callback = new InstanceContext(new ClientCallback());
MyServiceClient client = new MyServiceClient(callback);
client.Open();
client.Register();
Console.WriteLine("Press a key to exit");
Console.ReadKey();
client.Close();

Now if you run the server and then one or more clients, after 10 seconds you should see the clients updated every ten seconds. This is fine except that each time a client connected to the service a new service was created for each new client. If we wanted a single instance of the server to be connected to multiple clients we can simply change a few lines in the service code.

1. On the MyService implementation add the following attribute

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

2. In the Program.cs Main method make the following two changes

MyService service = new MyService();
ServiceHost serviceHost = new ServiceHost(service);

With the above we create a single instance of the MyService then assign it the the ServiceHost.

Quickstart WCF service and client

I’ve already got a post on WCF basics, but I had to quickly knock together a WCF service and client to try something out today and I thought it’d be useful to list the steps to create a real bare bones service and client in a single post.

Let’s begin with the service itself. I want to create a self hosted service running from a console app. so I can easily debug and control everything, so

1. Open a new instance of Visual Studio
2. Create a new console application.
3. Copy the following into the Main method

ServiceHost serviceHost = new ServiceHost(typeof(MyService));
serviceHost.Open();
Console.WriteLine("Service Running");
Console.ReadLine();
serviceHost.Close();

4. Add the reference to System.ServiceModel as well as a valid app.config. For example

<system.serviceModel>
   <behaviors>
      <serviceBehaviors>
         <behavior name="">
            <serviceMetadata httpGetEnabled="false" />
            <serviceDebug includeExceptionDetailInFaults="false" />
         </behavior>
      </serviceBehaviors>
   </behaviors>
   <services>
      <service name="WcfTest.MyService">
         <endpoint address="" binding="netTcpBinding" bindingConfiguration=""
                   contract="WcfTest.IMyService">
            <identity>
               <dns value="localhost" />
             </identity>
         </endpoint>
         <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
                    contract="IMetadataExchange" />
         <host>
            <baseAddresses>
               <add baseAddress="net.tcp://localhost:8732/MyService/" />
            </baseAddresses>
         </host>
      </service>
   </services>
</system.serviceModel>  

5. Create an interface with at least one method, as we’re calling the service MyService, let’s call the interface IMyService. You’ll need at least one method and the interface shold have a ServiceContract attribute and the method have an OperationContract, for example

[ServiceContract]
public interface IMyService
{
   [OperationContract]
   void SayHello(string name);
}

6. Implement the interface for example

public class MyService : IMyService
{
   public void SayHello(string name)
   {
      Console.WriteLine("Hello " + name);
   }
}

6. Run the application

Now to the client…

1. Open a new instance of Visual Studio
2. Create a console application
3. Add a service reference (use the url from the server, i.e. net.tcp://localhost:8732/MyService/mex from the service’s app.config)
4. Click Go
5. Click OK
6. Finally add the following code into the Main method

var client = new MyServiceClient();
client.SayHello("Scooby Doo");
client.Close();

Now we have a working service and client.