Category Archives: WCF

Remoting using WCF

It’s been a long while since I had to write any remoting code. However I came across a requirement to run a small out of process application which needed to be controlled by another application, I won’t bore you with the details, but suffice to say remoting seemed to be a good fit for this.

Let’s look at some code

Let’s start by creating the server/service. In this instance I will host the service in a Console application. So we need to create a Console solutions/project (mine’s named RemoteServer) and then (to allow us to reuse an interface file) add a Class library (mine’s named RemoteInterfaces).

Add the following to the class library

[ServiceContract]
public interface IRemoteService
{
   [OperationContract(IsOneWay = true)]
   void Write(string message);
}

Note: you’ll need a reference to System.ServiceModel in the RemoteInterfaces project, plus using System.ServiceModel; in the source

Add the class library as a reference to the RemoteServer console application.

Now, let’s create the implementation for the server…

[ServiceBehavior(
 ConcurrencyMode = ConcurrencyMode.Single,
 InstanceContextMode = InstanceContextMode.Single)]
public class RemoteService :
   IRemoteService
{
   private ServiceHost host;

   public void Start()
   {
      host = new ServiceHost(this);
      host.Open();
   }

   public void Stop()
   {
      if (host != null)
      {
         if (host.State != CommunicationState.Closed)
         {
            host.Close();
         }
      }
   }

   public void Write(string message)
   {
      Console.WriteLine(String.Format("[Service] {0}", message));
   }
}

We’re going to run this service as a singleton when the console starts, so in Program.cs we need to write the following

try
{
   var svc = new RemoteService();
   svc.Start();

   Console.ReadLine();

   svc.Stop();
}
catch (Exception e)
{
   Debug.WriteLine(e.Message);
}

Finally we need to put some configuration in place to tell WCF how this service is to be hosted, so in the console application, add an App.config (if not already available) and add the following

finally App.config looks like

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
    <services>
      <service name="RemoteServer.RemoteService">
        <endpoint binding="netTcpBinding"
                  contract="RemoteInterfaces.IRemoteService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8000/RemoteService"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel></configuration>

Client implementation

Now, lets create a client to tests this service. For simplicity, we’ll assume the server is run automatically, either at startup or via our client application, but we won’t bother writing code for this. So when you’re ready to test the client just ensure you’ve run the server console first. You’ll need to reference the class library with the IRemoteService (RemoteInterfaces) also.

Note: you’ll need a reference to System.ServiceModel in the RemoteClient project, plus using System.ServiceModel; in the source

Change the client Main method to include the following

var channelFactory = new ChannelFactory<IRemoteService>(
   new NetTcpBinding(),
   new EndpointAddress("net.tcp://localhost:8000/RemoteService"));
var channel = channelFactory.CreateChannel();

channel.Write("Hello World");

channelFactory.Close();

Now if you run this client, the server should output the Hello World text.

We’ve initially created this client by hard coding the endpoint etc. but it might be better if this was in the configuration.

In your App.config you could have the following

<system.serviceModel>
   <client configSource="Config\servicemodel-client-config.xml" />
</system.serviceModel>	

Note: Obviously the name of the file us upto you.

or we could place the service code directly in the App.config, it should look like this (if in an external config file)

<?xml version="1.0" encoding="utf-8"?>
<client>
   <endpoint name="RemoteServer.RemoteService"
      address="net.tcp://localhost:8000/RemoteService"
      binding="netTcpBinding"
      contract="RemoteInterfaces.IRemoteService">
      <identity>
         <servicePrincipalName value=""/>
      </identity>
   </endpoint>
</client>

Note: If placed within the App.config, wrap the client element in a system.serviceModel element

and now we can change our ChannelFactory in the Main method to look like this

var channelFactory = new ChannelFactory<IRemoteService>("*");

The configuration will thus be taken from the configuration file.

Let’s switch from using TCP to using a named pipe

So the previous code and configuration should work correctly using the TCP/IP protocol, but it does rely on a known port to be used. In scenarios where you’re deploying to a machine where you’re not 100% sure the port is available, you could ofcourse offer up several port options.

Another choice (which should also be more performant, although I’ve not tested this) for interprocess communications on the same machine, is to use a named pipe.

For this change the service’s App.config (or external file) on the server to use the following configuration

<services>
   <service name="RemoteServer.RemoteService">
      <endpoint binding="netNamedPipeBinding"
         contract="RemoteInterfaces.IRemoteService">
         <identity>
            <dns value="localhost"/>
         </identity>
       </endpoint>
       <host>
          <baseAddresses>
            <add baseAddress="net.pipe://localhost/RemoteServer/RemoteService"/>
          </baseAddresses>
       </host>
   </service>
</services>

and in the client code we could use

channelFactory = new ChannelFactory<IRemoteService>(
                new NetNamedPipeBinding(),
                new EndpointAddress("net.pipe://localhost/RemoteServer/RemoteService"));

or replacing with configuration we could use replace our client configuration with

<client>
   <endpoint name="RemoteServer.RemoteService"
      address="net.pipe://localhost/RemoteServer/RemoteService"
      binding="netNamedPipeBinding"
      contract="RemoteInterfaces.IRemoteService">
      <identity>
         <servicePrincipalName value=""/>
      </identity>
    </endpoint>
</client>

Debugging

You might at times find issues with your client not finding an endpoint, an ipc name or port etc. How can we check if our server is actually connected to a port or pipe?

For tcp/http protocols, we can use netstat, for example

netstat -a | findstr "8000"

this will list display all connections and listening ports (-a switch) and pipe these through the findstr application to display only those with 8000 in the output. Hence if we’re running a server off of port 8000 it should be listed and we’ll know that the server is (at least) running.

For ipc/pipe, the simplest way is via Powershell by running the following

[System.IO.Directory]::GetFiles("\\.\\pipe\\")

this will list all pipes, which might be a little over the top.

An alternative to the above is use the sysinternals PipeList executable.

Whilst we could use the following for old style remoting code (to find a named pipe)

[System.IO.Directory]::GetFiles("\\.\\pipe\\") | findstr "RemoteService"

unfortunately this does not work for WCF named pipes as these are converted to GUID’s. See Named Pipes in WCF are named but not by you (and how to find the actual windows object name).

Adding data to WCF headers

As I’ve covered this subject using WSE3, now to look at adding an SSO token to a WCF header.

Configuration

In your App.config you’ve probably got something like

<system.serviceModel>
   <client configSource="Config\servicemodel-client-config.xml" />
   <bindings configSource="Config\servicemodel-bindings-config.xml" />
</system.serviceModel>

We’re going to add two more configuration files, as follows

<system.serviceModel>
   <client configSource="Config\servicemodel-client-config.xml" />
   <bindings configSource="Config\servicemodel-bindings-config.xml" />
   <!-- Additions -->
   <behaviors configSource="Config\servicemodel-behaviors-config.xml" />
   <extensions configSource="Config\servicemodel-extensions-config.xml" />
</system.serviceModel>

As the names suggest, these file will include the config for behaviors and extensions.

Let’s take a look at the servicemodel-behaviors-config.xml first

<?xml version="1.0" encoding="utf-8" ?>
<behaviors>
   <endpointBehaviors>
      <behavior name="serviceEndpointBehaviour">
         <ssoEndpointBehaviorExtension />
         <!-- insert any other behavior extensions here -->
      </behavior>
   </endpointBehaviors>
</behaviors>

Now we need to actually define what implements ssoEndpointBehaviorExtension. So in the servicemodel-extensions-config.xml configuration, we might have something like the following

<?xml version="1.0" encoding="utf-8" ?>
<extensions>
   <behaviorExtensions>
      <add name="ssoEndpointBehaviorExtension"
            type="SsoService.SsoEndpointBehaviorExtensionElement, SsoService"/>
      <!-- insert other extensions here -->
   </behaviorExtensions>
</extensions>

So as we can see, the ssoEndpointBehaviorExtension behavior is associated with the SsoService assembly and the type SsoEndpointBehaviorExtensionElement.

Implementing the behavior/extension

Unlike WSE3 we do not need to use an attribute to associate the extension with a service call.

Let’s start by looking at the SsoEndpointBehaviorExtensionElement behavior extension.

public class SsoEndpointBehaviorExtensionElement : BehaviorExtensionElement
{
   public override Type BehaviorType
   {
      get { return typeof(SsoEndpointBehavior); }
   }
   
   protected override object CreateBehavior()
   {
      return new SsoEndpointBehavior();
   }
}

The code above relates to the actual extension element, so really just creates the actual behavior when required. Here’s the SsoEndpointBehavior.

public class SsoEndpointBehavior : IEndpointBehavior
{
   public void AddBindingParameters(ServiceEndpoint endpoint, 
                 BindingParameterCollection bindingParameters)
   {
   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
                 ClientRuntime clientRuntime)
   {
      clientRuntime.MessageInspectors.Add(new SsoMessageInspector());
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
                 EndpointDispatcher endpointDispatcher)
   {
   }

   public void Validate(ServiceEndpoint endpoint)
   {
   }
}

This code simply adds the inspector to the message inspector. Finally let’s look at the code that actual intercepts the send requests to add the SSO token to the header.

public class SsoMessageInspector : IClientMessageInspector
{
   public object BeforeSendRequest(ref Message request, IClientChannel channel)
   {
      request.Headers.Add(MessageHeader.CreateHeader("ssoToken", 
              String.Empty, 
              SsoManager.TokenString);
      return null;
   }

   public void AfterReceiveReply(ref Message reply, object correlationState)
   {
   }
}

In the above code, we create an addition to the message header, with the name “ssoToken” followed by any namespace and then the value we wish to store with the header item. In this case our SSO token.

void return methods in WCF (IsOneWay)

Don’t forget, if you’re implementing a fire and forget style method call in WCF, to mark it as one way.

In situations where you do not need or want to return a value from the server or handle exceptions from the client. You must mark the method’s operation contract as IsOneWay=true.

For example (if this is the service contract)

[ServiceContract]
public interface IProjectManager
{
   [OperationContract(IsOneWay=true)]
   void Run();
}

Without the IsOneWay=true the method will get called by the client but will block and may eventually timeout.

Basically with a one way operation the client calls the service and the service may queue the call to be dispatched one at a time. If the number of queued calls exceeds the queue’s capacity the client will block. In the case of a one way call the message is queued but the client unblocked. It is not an async call but may appear that way.

By default IsOneWay is false, hence the need to add the option to the attribute explicitly.

Enumerations in WCF

Like other data types designed to go over the WCF wire (as it were) we need to mark the enum with a DataContractAttribute. Unlike classes, which use the DataMemberAttribute for any published methods we use the EnumMemberAttribute. For example

[DataContract]
public enum Status
{
   [EnumMember]
   None,
   [EnumMember]
   Running,
   [EnumMember]
   Failed,
   [EnumMember]
   Succeeded
}

Don’t forget to add a FlagsAttribute if you are requiring the enum to work as flags otherwise you’ll get an error from WCF when combining your flags, as the value will be unexpected.

Derived and base classes in WCF

This is a short post on something that caught me out, primarily due to the awful client side error message.

The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.

I was implementing a WCF service to allow my client to get historic data from the service. But as the History object might become large I also wanted a HistorySummary object with the bare minimum data. So for example my client UI would list the history summary data and only when the user clicked on the summary would the full data get loaded.

So I implemented my HistorySummary (abridged version below)

[DataContract]
public class HistorySummary
{
   [DataMember]
   public string Name { get; set; }
   // ... other properties
}

From this I derived my History object (also abridged)

[DataContract]
public class History : HistorySummary
{
   [DataMember]
   public string[] Reports { get; set; }
   // ... other properties
}

If you’re experienced in WCF you’ll immediately spot the problem straight away.

I built the server and ran it, no problems. I regenerated the proxies and ran the client and bang ! I get the less than helpful error message shown above.

KnownTypes was the problem. Easy to forget. The base class, HistorySummary should have looked like this

[DataContract]
[KnownType(typeof(History))]
public class HistorySummary
{
   [DataMember]
   public string Name { get; set; }
   // ... other properties
}

Handling data in WCF headers (service-side)

So my previous post looked at adding data into the headers of the WCF service calls from the client-side perspective.

Ofcourse for this to be of any use we need the service to handle the extraction of this header data. So this post is mean’t to cover the basics of this. First we need to create the extension, so we inherit from BehaviorExtensionElement (just as we did on the client)

public class SecurityTokenEndpointBehaviourExtensionElement : BehaviorExtensionElement
{
   public override Type BehaviorType
   {
      get { return typeof(SecurityTokenServiceBehaviour); }
   }
   protected override object CreateBehavior()
   {
      return new SecurityTokenServiceBehaviour();
   }
}

Now we need to create an implementation of the IServiceBehavior (on the client this is the IEndpointBehavior)

public class SecurityTokenServiceBehaviour : IServiceBehavior
{
   public void Validate(ServiceDescription serviceDescription, 
                        ServiceHostBase serviceHostBase)
   {
   }

   public void AddBindingParameters(ServiceDescription serviceDescription, 
                         ServiceHostBase serviceHostBase, 
                         Collection<ServiceEndpoint> endpoints, 
                         BindingParameterCollection bindingParameters)
   {
   }

   public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
                         ServiceHostBase serviceHostBase)
   {
      foreach(ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
      {
         foreach(EndpointDispatcher epd in cd.Endpoints)
         {
            epd.DispatchRuntime.MessageInspectors.Add(new SecurityTokenMessageInspector());
         }
      }
   }
}

and finally we implement an IDispatchMessageInspector (on the client this would be the IClientMessageInspector)

public class SecurityTokenMessageInspector : IDispatchMessageInspector
{
   public object AfterReceiveRequest(ref Message request, 
                     IClientChannel channel, 
                     InstanceContext instanceContext)
   {
      return null;
   }

   public void BeforeSendReply(ref Message reply, object correlationState)
   {
   }
}

Okay so we’ve got all the code in place but now we need to tie this into WCF using the configuration (ofcourse if you prefer you can do this in code).

Just as we need to do in the client, we need to register the extension in an extensions element and again as per the client we then need to link the behaviour to the extension, see the App.config for this service below

<system.serviceModel>
   <behaviors>
      <serviceBehaviors>
         <behavior name="MyBehavior">
            <serviceMetadata httpGetEnabled="true" />
            <serviceDebug includeExceptionDetailInFaults="true" />
            <!--our extension -->
            <securityTokenExtension /> 
         </behavior>
      </serviceBehaviors>
   </behaviors>
   <services>
      <service behaviorConfiguration="MyBehavior" name="SimpleService.MyService">
        <endpoint address="MyService" binding="basicHttpBinding"
          bindingConfiguration="" contract="SimpleService.IMyService" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9095/" />
          </baseAddresses>
        </host>
      </service>
   </services>
   <extensions>
      <behaviorExtensions>
        <add name="securityTokenExtension" 
           type="SimpleService.SecurityTokenEndpointBehaviourExtensionElement, SimpleService" />
      </behaviorExtensions>
   </extensions>
</system.serviceModel>

Finally, how do we get the value stored in the header on the service ?

The following code shows how we extract the value from the header named “myToken”, the generic argument shown in the method call GetHeader represents the type we expect the data to be.

public object AfterReceiveRequest(ref Message request, 
                  IClientChannel channel, 
                  InstanceContext instanceContext)
{
   int idx = request.Headers.FindHeader("myToken", String.Empty);
   if(idx >= 0)
   {
      Console.WriteLine(String.Format("Header value: {0}", 
                       request.Headers.GetHeader<string>(idx));
   }
   return null;
}

Adding data to WCF message headers (client-side)

When working with WCF you may find a need to add data to the message headers, for example maybe you wish to add some form of authentication token or the likes.

The first thing we need to do is create a BehaviorExtensionElement and add the relevant configuration to the App.Config.

public class SecurityTokenEndpointBehaviourExtensionElement : BehaviorExtensionElement
{
   public override Type BehaviorType
   {
      get { return typeof(SecurityTokenEndpointBehaviour); }
   }
   protected override object CreateBehavior()
   {
      return new SecurityTokenEndpointBehaviour();
   }
}

Now we need the corresponding entry in the config file for the extension and also the behaviour that our endpoint will map to

<behaviors>
   <endpointBehaviors>
      <behavior name="serviceEndpointBehaviour">
         <securityTokenExtension />
      </behavior>
   </endpointBehaviors>
</behaviors>
<extensions>
   <behaviorExtensions>
      <add name="securityTokenExtension"
	type="PutridParrot.SecurityTokenEndpointBehaviourExtensionElement, PutridParrot" />
   </behaviorExtensions>
</extensions>

As you can see the configuration basically tells WCF to use our BehaviorExtensionElement which then creates the behaviour. This behaviour then adds inspectors to the client as in the sample below

public class SecurityTokenEndpointBehaviour : IEndpointBehavior
{
   public void AddBindingParameters(ServiceEndpoint endpoint, 
                   BindingParameterCollection bindingParameters)
   {
   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
                   ClientRuntime clientRuntime)
   {
      clientRuntime.MessageInspectors.Add(new SecurityTokenMessageInspector());
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
                    EndpointDispatcher endpointDispatcher)
   {
   }

   public void Validate(ServiceEndpoint endpoint)
   {
   }
}

So this code is very simple. In this case we’re simply adding a new message inspector and it’s this IClientMessageInspector implementation that adds the token to the WCF headers. As shown below

public class SecurityTokenMessageInspector : IClientMessageInspector
{
   public object BeforeSendRequest(ref Message request, IClientChannel channel)
   {
      request.Headers.Add(MessageHeader.CreateHeader("myToken", 
                          String.Empty, SecurityToken.Token));
      return null;
   }

   public void AfterReceiveReply(ref Message reply, object correlationState)
   {
   }
}

The code above adds a new message header with the name “myToken” and a value of SecurityToken.Token (just assume this is a singleton which creates and stores a security token).

Before this will work on the client we need to configure the end point to use the behaviorConfiguration defined previously, so now in the endpoint add

behaviorConfiguration="serviceEndpointBehaviour"

So the client configuration will look something like

<client>
   <endpoint address="http://localhost:9095/MyService" 
            binding="basicHttpBinding" contract="MyService.IMyService"                    
            behaviorConfiguration="serviceEndpointBehaviour"/>
</client>

WCF Rest

Creating a REST style interface with WCF is fairly simple. The steps are listed briefly below, and in more depth below the list of steps.

1. Create your interface/service contract
2. Annotate the methods with WebGet or WebInvoke attributes
3. Create the implementation of the interface
4. Declare the endpoint within the configuration file (or in code). The binding should be webHttpBinding and should have an endpoint behaviour specificied with WebHttp
5. If need be declare the http baseAddress

In more depth

1. Create your interface/service contract
and
2. Annotate the methods with WebGet or WebInvoke attributes

[ServiceContract]
public interface IRestService
{
   [OperationContract]
   [WebGet(UriTemplate = "projects")]
   IList GetProjects();

   [OperationContract]
   [WebGet(UriTemplate = "execute/{projectName}")]
   void Execute(string projectName);
}

Note: Note to self. Don’t forget to put the ServiceContract attribute on the interface !

I’ve implemented both methods a GET methods. Assuming a baseAddress of http://localhost:8733/MyService/ to call these methods through a web browser we can simply type http://localhost:8733/MyService/projects and http://localhost:8733/MyService/execute/MyProject respectively.

3. Create the implementation of the interface

No need to list source code for this, simple implement the interface you created.

4. Declare the endpoint within the configuration file (or in code). The binding should be webHttpBinding and should have an endpoint behaviour specificied with WebHttp
and
5. If need be declare the http baseAddress

The key bit to getting everything to work is the configuration file. I’m self hosting for this example so implementing the code in the App.config

<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="rest">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="StandardPlugins.MonitorService">
        <endpoint address="" binding="webHttpBinding" bindingConfiguration=""
            contract="StandardPlugins.IRestService" behaviorConfiguration="rest">
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/MyService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
</system.serviceModel>

Note: The REST methods should be accessible via HTTP, hence the binding is webHttpBinding and the baseAddress is http. A behaviorConfiguration is required with the webHttp element.

Further reading

http://msdn.microsoft.com/en-us/magazine/dd315413.aspx#id0070050
http://msdn.microsoft.com/en-us/library/vstudio/bb412172(v=vs.90).aspx

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.