Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In .NET remoting what is the difference between RemotingConfiguration.RegisterWellKnownServiceType and RemotingServices.Marshal?

Tags:

c#

.net

remoting

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);
like image 781
David Basarab Avatar asked Jan 29 '09 21:01

David Basarab


People also ask

Which of the following channel is supported in .NET remoting?

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.

Which of the following methods in .NET remoting is used?

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.

What is .NET remoting define the use of channels?

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.


2 Answers

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.

like image 115
David Basarab Avatar answered Sep 17 '22 10:09

David Basarab


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.

like image 39
Daniel Flower Avatar answered Sep 21 '22 10:09

Daniel Flower