The ServiceContainer, implementing the IServiceContainer Interface is used to store and retrieve services. it is used for Dependency Injection, a very important concept that allows separating independent components, and is widely discussed over the web. However, one drawback of this implementation is it does not work with .net  remoting… When you try to add a remote proxy object to the container you’ll get the following exception: “The service instance must derive from or implement XXX“. Follow this simple example of a remote calculator client (I’ll add the server code at the end) and than we’ll understand what’s wrong using our friend – the reflector:

TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel);
ICalculator calculator =(ICalculator)Activator.GetObject(
        typeof(ICalculator),"tcp://localhost:1235/RemoteCalculator");

IServiceContainer serviceContainer = new ServiceContainer();
serviceContainer.AddService(typeof(ICalculator), calculator);

Now open reflector and locate the AddService implementation – see the type check code:

...
if ((!(serviceInstance is ServiceCreatorCallback) &&
    !serviceInstance.GetType().IsCOMObject) &&
    !serviceType.IsAssignableFrom(serviceInstance.GetType()))
{
    throw new ArgumentException(SR.GetString("ErrorInvalidServiceInstance", 
                                  new object[]  { serviceType.FullName }));
}
...

But, the calculator object is actually a proxy to a calculator, which does not implement the interface by himself and this is why the exception is thrown. The missing line here should be:

&& !serviceInstance.GetType().IsMarshalByRef

So, if you do want to use ServiceContainer with Remoting, a possible solution would be to inherit from it and implement the virtual method AddService yourself, adding the missing line.

Here is the server code I used:

public interface ICalculator
{
    int Add(int a, int b);
}
...
class Calculator : MarshalByRefObject, ICalculator
{
    int ICalculator.Add(int a, int b)
    {
        Console.WriteLine(string.Format("ICalculator.Add({0}, {1})", a, b));
        return a + b;
    }
}
...
TcpChannel channel = new TcpChannel(1235);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(Calculator), "RemoteCalculator", WellKnownObjectMode.Singleton);

Tags :

Post a Comment