programming4us
programming4us
ENTERPRISE

Programming .NET Components : Building a Distributed Application (part 1) - Programmatic Channel Registration

9/29/2012 1:56:56 AM
Finally, after so many definitions and abstractions, it's time to put it all to use and see how to build a server, a host app domain to host the server object, and a client application to consume the remote object. Both the host and the client application need to indicate to .NET how they intend to use remoting. The host needs to register with .NET the channels and formats on which it's willing to accept remote calls, the remote types it's willing to export, their activation modes, and their URIs (if applicable). The client application needs to register with .NET the types it wants to access remotely, and any channels to be used for callbacks. There are two ways to achieve all this: programmatically and administratively. If you use programmatic configuration, you gain maximum flexibility because at any time you can change the activation modes, object locations, and channels used. Both the client and the host can use programmatic configuration. If you use administrative configuration, you save your remoting settings in a configuration file. Both the client and the server can use administrative configuration. You can also mix and match (i.e., have some settings in the configuration files and programmatically configure others), although normally you use one or the other of these methods, not both at the same time. Administrative configuration lets you change the settings and affect the way your distributed application behaves, even after deployment; it's the preferred way to handle remoting in most cases. This section demonstrates both techniques using the same sample application. I will explain programmatic configuration first and, armed with the understanding of the basic steps, will then examine the administrative configuration settings.

1. Programmatic Channel Registration

A remoting channel is any component that implements the IChannel interface, defined in the System.Runtime.Remoting.Channels namespace. You rarely need to interact with a channel object directly—all you have to do is register them. Out of the box, .NET provides three implementations of the IChannel interface: the TcpChannel, HttpChannel, and IpcChannel classes, defined in the System.Runtime.Remoting.Channels.Tcp, System.Runtime.Remoting.Channels.Http, and System.Runtime.Remoting.Channels.Ipc namespaces, respectively. The host application needs to register which channels it wishes to use, using the static method RegisterChannel( ) of the ChannelServices class:

    public sealed class ChannelServices
    {
       public static void RegisterChannel(IChannel channel);
       //Other methods
    }

Typically, the host will put the channel registration code in its Main( ) method, but it can register the channels anywhere else, as long as the registration takes place before remote calls are issued. Note that you can register the same channel type only once per app domain, unless you explicitly assign it a different name, as described later.

1.1. Host channel registration

The host must register at least one channel if it wants to export objects. To register a TCP or HTTP channel, the host first creates a new channel object, providing as a construction parameter the port number associated with this channel. Next, the host registers the new channel. For example:

    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Tcp;
      
    //Registering TCP channel
    IChannel channel = new TcpChannel(8005);
    ChannelServices.RegisterChannel(channel);

When a new remote call is accepted, the channel grabs a thread from the thread pool and lets it execute the call, while the channel continues to monitor the port. This way, .NET can serve incoming calls as soon as they come off the channel. Note that the number of concurrent calls .NET remoting can service is subject to the thread-pool limitation. Once the pool is exhausted, new requests are queued until requests in progress are complete.

To register an IPC channel, the host provides the IpcChannel constructor with the pipe's name:

    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Ipc;

    //Registering IPC channel
    IChannel ipcChannel = new IpcChannel("MyHost");
    ChannelServices.RegisterChannel(ipcChannel);

The named pipe is a global resource on the host machine, and therefore it must be unique machine-wide. No other host on the same machine can open a named pipe with the same name; doing so will yield a RemotingException.

The host can register multiple channels, like so:

    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Tcp;
    using System.Runtime.Remoting.Channels.Http;
    using System.Runtime.Remoting.Channels.Ipc;
      
    //Registering TCP channel
    IChannel tcpChannel = new TcpChannel(8005);
    ChannelServices.RegisterChannel(tcpChannel);
      
    //Registering http channel
    IChannel httpChannel = new HttpChannel(8006);
    ChannelServices.RegisterChannel (httpChannel);

    //Registering IPC channel
    IChannel ipcChannel = new IpcChannel("MyHost");
    ChannelServices.RegisterChannel(ipcChannel);

When the host instantiates a channel, .NET creates a background thread to open a socket and listen to activation requests on the port. As a result, you can run blocking operations after creating and registering a channel, because you won't affect the thread monitoring the channel. For example, this is valid host-side registration code:

    static void Main( )
    {
       //Registering TCP channel
       IChannel channel = new TcpChannel(8005);
       ChannelServices.RegisterChannel(channel);
      
       Thread.Sleep(Timeout.Infinite);
    }

An inherent limitation of network programming is that on a given machine you can open a given port only once. Consequently, you can't open multiple channels on the same port on a given machine. For example, you can't register channels this way:

    //You can't register multiple channels on the same port
    IChannel tcpChannel = new TcpChannel(8005);
    ChannelServices.RegisterChannel(tcpChannel);
      
    IChannel httpChannel = new HttpChannel(8005);
    ChannelServices.RegisterChannel(httpChannel);

Registering multiple channels targeting the same port number causes an exception to be thrown at runtime. In addition, you can register a channel type only once, even if you use different ports:

    //You can only register a channel once, so this will not work:
      
    IChannel tcpChannel1 = new TcpChannel(8005);
    ChannelServices.RegisterChannel(tcpChannel1);
      
    IChannel tcpChannel2 = new TcpChannel(8007);
    ChannelServices.RegisterChannel(tcpChannel2);//Throws RemotingException

The same is true for the IPC channel—the host can register only a single IPC channel per app domain.

When the host application shuts down, .NET automatically frees the port (or the named pipe) so other hosts on the machine can use it. However, it's customary that as soon as you no longer need the channels, you unregister them explicitly using the static method UnregisterChannel( ) of the ChannelServices class:

    IChannel channel = new TcpChannel(8005);
    ChannelServices.RegisterChannel(channel);
      
    /* Accept remote calls here */
      
    //When done—unregister channel(s):
    ChannelServices.UnregisterChannel(channel);

1.2. Channels and formats

The default constructors shown so far automatically select the appropriate default formatter. By default, the TcpChannel and IpcChannel classes use the binary formatter to format messages between the client and the host. The HttpChannel class uses the SOAP formatter by default. However, as stated previously, you can combine any channel with any format. The channel classes provide the following constructors:

    public class TcpChannel : <base types>
    {
       public TcpChannel(IDictionary properties,
                         IClientChannelSinkProvider clientSinkProvider,
                         IServerChannelSinkProvider serverSinkProvider);
        /* Other constructors and methods  */
    }
      
    public class HttpChannel : <base types>
    {
        public HttpChannel(IDictionary properties,
                           IClientChannelSinkProvider clientSinkProvider,
                           IServerChannelSinkProvider serverSinkProvider);
        /* Other constructors and methods  */
    }
    public class IpcChannel : <base types>
    {
       public IpcChannel(IDictionary properties,
                         IClientChannelSinkProvider clientSinkProvider,
                         IServerChannelSinkProvider serverSinkProvider);
        /* Other constructors and methods  */
    }


					  

These constructors accept a collection of key/value pairs and two sink interfaces. The collection is a dictionary of predetermined channel-configuration properties, such as the new channel's name and the port number. The two sink interfaces are where you can provide a formatter instead of accepting the default. The clientSinkProvider parameter registers a channel on the client's side (when client-side registration takes place for callbacks); the serverSinkProvider parameter registers a channel on the host's side. The available formatters for the host are SoapServerFormatterSinkProvider and BinaryServerFormatterSinkProvider, implementing the IServerChannelSinkProvider interface. The available formatters are SoapClientFormatterSinkProvider and BinaryClientFormatterSinkProvider, implementing the IClientChannelSinkProvider interface. The details of these interfaces and format-providing classes are immaterial; the important thing is that you can use one to explicitly force a message format.

Refer to the MSDN Library for more information on the configuration parameters and the way they affect the channels.


Here is how to register a SOAP formatter using a TCP channel on the host side:

    IServerChannelSinkProvider formatter;
    formatter = new SoapServerFormatterSinkProvider( );
      
    IDictionary channelProperties = new Hashtable( );
    channelProperties["name"] = "MyServerTCPChannel";
    channelProperties["port"] = 8005;
      
    IChannel channel = new TcpChannel(channelProperties,null,formatter);
    ChannelServices.RegisterChannel(channel);

Note that the second construction parameter is ignored. When doing the same on the client side, you need not provide a port number, and you provide the formatter as the second (instead of the third) parameter:

    IClientChannelSinkProvider formatter;
    formatter = new SoapClientFormatterSinkProvider( );
      
    IDictionary channelProperties = new Hashtable( );
    channelProperties["name"] = "MyClientTCPChannel";
      
    IChannel channel = new TcpChannel(channelProperties,formatter,null);
    ChannelServices.RegisterChannel(channel);
Other  
 
Video
PS4 game trailer XBox One game trailer
WiiU game trailer 3ds game trailer
Top 10 Video Game
-   Renoir [PS4/XOne/PC] Kickstarter Trailer
-   Poly Bridge [PC] Early Access Trailer
-   Renoir [PS4/XOne/PC] Gameplay Explanation Trailer
-   Renoir [PS4/XOne/PC] More About Trailer
-   King's Quest: A Knight to Remember [PS3/PS4/X360/XOne/PC] Complete Collection Trailer
-   Samurai Warriors Chronicles 3 | Announcement Trailer
-   FIFA 16 | No Touch Dribbling with Lionel Messi
-   Why We're Cautiously Optimistic For The Final Fantasy VII Remake
-   Civilization: Beyond Earth – Rising Tide [PC] E3 Gameplay Walkthrough
-   Why We're Excited For the FFVII Remake
-   Mortal Kombat X | Predator Brutality
-   Mortal Kombat X | Predator Fatality
-   Poly Bridge [PC] Early Access Trailer
-   Silence: The Whispered World 2 [PS4/XOne/PC] Cinematic Trailer
-   Devilian [PC] Debut Trailer
Game of War | Kate Upton Commercial
programming4us
 
 
programming4us