Category Archives: Remoting

Remoting in C# (legacy code)

In another post I looked at remoting using WCF but what were things like before WCF (or what’s an alternative to WCF)? I thought I’d post just the bare bones for getting a really simple service and client up and running.

Note: Microsoft recommends new remoting code uses WCF, so this post is more for understanding legacy code.

Note: I am not going to go into the lifecycle, singletons/single instances etc. here, I’m just going to concentrate on the code to get something working.

The Server

As per my previous post on WCF remoting, we’re going to simply create a console application to act as our server, so go ahead an create one (mine’s named OldRemoteServer) and then add the following

public interface IRemoteService
{
   void Write(string message);
}

into a file of it’s own, then our client can link to it in our client’s Visual Studio solution.

Here’s an implementation for the above

public class RemoteService : MarshalByRefObject, IRemoteService
{
   public void Write(string message)
   {
      Console.WriteLine(message);
   }
}

Note: The implementation needs to be derived from MarshalByRefObject or the class needs to be marked with the Serializable attribute or implement ISerializable which obviously makes sense. We’re solely going to look at MarshalByRefObject implementation for now as these will be passed by reference to the client, whereas the serializable implementations are aimed at passing by value.

Now let’s put some code in the Main method of our Console app.

var channel = new TcpChannel(1002);
ChannelServices.RegisterChannel(channel, false);

RemotingConfiguration.RegisterWellKnownServiceType(
  typeof(RemoteService), 
  "Remote", 
   WellKnownObjectMode.Singleton);

// now let's ensure the console remains open
Console.ReadLine();

In the above code we’re using a Tcp channel with the port number 1002 and in the RegisterWellKnownServiceType, we’re registering the service type (this should be the implementation, not the interface) and supply a name “Remote” for it. In this case I’m also setting it to be a Singleton.

You’ll need to add a reference to System.Runtime.Remoting and the following using clauses

using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

The Client

Create another Console application to simply test this and add the file with the IRemoteService interface.

I’ve simply added it by selecting the client solution, the Add… | Existing Item, locate the file and instead of clicking the Add button select the dropdown to Add As Link. Then if you change the interface it’ll be immediately reflected in the client – ofcourse in a more complex application we’d have the interfaces in their own assembly.

Now to get the client to call the server we simply place the following in the Main method of the Console app.

var obj = (IRemoteService)Activator.GetObject(
   typeof(IRemoteService), 
   "tcp://localhost:1002/Remote");

obj.Write("Hello World");

In the above you’ll see that we use the Activator to get an object and supply the type, then the next line shows we’re using the Tcp channel, port 1002 as set up in the server and the name from the server we game our object “Remote”.

This creates a transparent proxy which we then simply call the interface method Write on.

Configuration

In the above example code I’ve simply hard-coded the configuration details but ofcourse we can create a .config file to instead handle such configurations.

Let’s replace all the server Main method code with the following

RemotingConfiguration.Configure("Server.config", false);

Add an App.config to the project, we’re going to rename it Server.config for this example and ensure that the files’s properties (in Visual Studio) are set to Copy Always (or Copy if newer) to ensure the copy in the bin folders is upto date.

Now here’s the Server.config which recreates the singleton, tcp, port 1002 settings previously handled in code

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
  <application>
    <service>
      <wellknown
        type="OldRemoteServer.RemoteService, OldRemoteServer"
        objectUri="Remote"
        mode="Singleton" />
    </service>
    <channels>
      <channel ref="tcp" port="1002"/>
    </channels>
  </application>

  </system.runtime.remoting>
</configuration>

Now if you run the server and then the client, everything should work as before.

Next up, let’s set the client up to use a configuration file…

So we’ll add an App.config file to the client now, but let’s name it Client.config and again set the Visual Studio properties to ensure it’s always copied to the bin folder.

Add the following to the configuration file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <client>
        <wellknown 
          type="OldRemoteServer.RemoteService, OldRemoteServer" 
          url="tcp://localhost:1002/Remote" />
      </client>
    </application>
  </system.runtime.remoting>
</configuration>

It might seem a little odd that we’re declaring the type as the implementation within the server code, but the reason will hopefully become clear.

Add a reference within the client to the RemoteServer (if you have the implementation in a DLL, all the better, we didn’t do that, so I’m referencing the server EXE itself). This now give us access to the implementation of the RemoteService.

Change the client Main method to

RemotingConfiguration.Configure("Client.config", false);

var obj = new RemoteService();
obj.Write("Hello World");

don’t forget to add the using clause

using System.Runtime.Remoting;

This bit might seem a little strange, based upon what we’ve previously done and how we’ve kept a separation of interface and implementation. Aren’t we now simply creating a local instance of the RemoteService, you might ask.

Well try it, run the server and then the client and you’ll find .NET has created a transparent proxy for us and calls to the RemoteService will in fact go to the server.

Whilst this makes things very easy, I must admit I prefer to not reference the implementation of the RemoteService.

What about named pipes?

Let’s now look at the changes to use the IPC protocol (for implementing named pipes) in .NET remoting. I’ll just briefly cover the changes required to implement this.

To start with let’s rewrite the server and client in code. So first the Main method in the server should now look like

var channel = new IpcChannel("ipcname");
ChannelServices.RegisterChannel(channel, false);

RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteService),
   "Remote",
   WellKnownObjectMode.Singleton);

Console.ReadLine();

So the only real difference from the Tcp implementation is the use of an IpcChannel and the name supplied instead of a port.

The client then looks like this

var obj = (IRemoteService)Activator.GetObject(
   typeof(IRemoteService), 
   "ipc://ipcname/Remote");

obj.Write("Hello World");

Simple enough.

Now let’s change the code to use a configuration file.

The server Main method should now look like this

RemotingConfiguration.Configure("Server.config", false);
Console.ReadLine();

and the Server.config should look like this

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
  <application>
    <service>
      <wellknown
        type="OldRemoteServer.RemoteService, OldRemoteServer"
        objectUri="Remote"
        mode="Singleton" />
    </service>
    <channels>
      <channel ref="ipc" portName="ipcname"/>
    </channels>
  </application>

  </system.runtime.remoting>
</configuration>

The client code should be

RemotingConfiguration.Configure("Client.config", false);
var obj = new RemoteService();
obj.Write("Hello World");

and it’s Client.config should look like this

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <client>
        <wellknown 
          type="OldRemoteServer.RemoteService, OldRemoteServer" 
          url="ipc://ipcname/Remote" />
      </client>
    </application>
  </system.runtime.remoting>
</configuration>

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).