In .NET remoting what is the difference between RemotingConfiguration.RegisterWellKnownServiceType and RemotingServices.Marshal?
What I want to do is create an object in a Windows Service, then put it in as a remoting object and have the Windows Service and the Client both act on the remoting object.
I thought the below code would accomplish this.
FooRemoting foo = new FooRemoting();
RemotingConfiguration.RegisterWellKnownServiceType(typeof(FooRemoting), serverName, WellKnownObjectMode.Singleton);
RemotingServices.Marshal(foo);
NET ships with two remoting types that support HTTP and TCP/IP protocols. Each provides a client channel, a server channel, and a combined sender-receiver channel. The default formatters support binary and Simple Object Access Protocol (SOAP) serialization.
RegisterChannel(channel); Register the remotable class with the remoting framework. For a server-activated object, the RegisterWellKnownServiceType() method of the RemotingConfiguration class is used to perform this registration, as follows: //Register a remote object with the remoting framework RemotingConfiguration.
A channel is an object that transports messages across remoting boundaries such as application domains, processes, and computers. The . NET Framework provides implementations for HTTP and TCP channels to enable communication of messages over the HTTP and TCP protocols, respectively. A channel has two endpoints.
This is what I found.
RemotingConfiguration.RegisterWellKnownServiceType(typeof(FooRemoting),
serverName, WellKnownObjectMode.Singleton);
RegisterWellKnownServiceType will create the object and make it a Singleton to any client that consumes it, but a reference by the server is not created. The object is not created until a client ask for it, and the same object is used for any other clients.
RemotingServices.Marshal(foo);
Marshal will register an object that has been created by the server, in this case a windows service. Then server will then have reference to the object and the clients will consume the same object.
My issue was using the Marshal to register the remoting object. Over time the remoting object will disappear for clients to consume, i.e. no longer on the remoting object. The service would still keep its reference. Then I tried the RegisterWellKnownServiceType and the clients keep getting the correct reference, however I could not get the service to have a reference to the same object.
The solution is overriding the remoting object in this case FooRemoting. If I overrode the InitializeLifetimeService and returned null, the client would never lose connection, and the service will, keep the connection.
public override object InitializeLifetimeService()
{
//return base.InitializeLifetimeService();
return null;
}
In order to keep the object created by the service and have the client to use the same object you must use
RemotingServices.Marshal(foo);
and override InitializeLifetimeService to return null.
It is possible to expose MarshalByRefObjects which have parameterful constructors over remoting, and it's possible for users of the class to only deal with its interface.
I have created a small proof of concept project. It has 3 projects: Server, Client, and Core. Server and Client both reference Core but do not reference each other.
In core, we define a service interface:
namespace Core
{
public interface ICountingService
{
int Increment();
}
}
The server defines the concrete implementation, which the client doesn't have a reference to:
namespace Server
{
public class CountingService : MarshalByRefObject, ICountingService
{
private static int _value = 0;
public CountingService(int startValue)
{
_value = startValue;
}
public int Increment()
{ // not threadsafe!
_value++;
return _value;
}
}
}
The important bits to note are that it has a constructor with a parameter, it is a MarshalByRefObject, and it implements the interface in the core project.
The server project is a console app which sets up a remoting channel (arbitrarily over HTTP for this example), creates the service, and registers it with remoting:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace Server
{
class Program
{
static void Main(string[] args)
{
HttpServerChannel serverChannel = new HttpServerChannel(8234);
ChannelServices.RegisterChannel(serverChannel, false);
// Following line won't work at runtime as there is no parameterless constructor
//RemotingConfiguration.RegisterWellKnownServiceType(typeof(CountingService),
// "CountingService.rem", WellKnownObjectMode.Singleton);
CountingService countingService = new CountingService(5);
RemotingServices.Marshal(countingService, "CountingService.rem");
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
}
}
The above code has registered the URL http://localhost:8234/CountingService.rem which holds the instantiated service, which will start counting from 5.
The client, also a console app, can then get a reference, using the interface class:
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Core;
namespace Client
{
class Program
{
static void Main(string[] args)
{
HttpClientChannel serverChannel = new HttpClientChannel();
ChannelServices.RegisterChannel(serverChannel, false);
for (int i = 0; i < 5; i++)
{
ICountingService countingService =
(ICountingService)Activator.GetObject(typeof(ICountingService),
"http://localhost:8234/CountingService.rem");
int newValue = countingService.Increment();
Console.WriteLine("Value is " + newValue);
}
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
}
}
When the server and client are run, it prints values from 6 to 10.
Summary: client knows only about the interface; implementation constructor can have parameters; instantiation can be controlled by your own code rather than by .NET. Very useful when dealing with constructor-based dependency injection with remoting objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With