Programming Examples

Are you a Programmer or Application Developer or a DBA? Take a cup of coffee, sit back and spend few minutes here :)

Generic Remote Interface Explained

1. Introduction to Generic Interface Example

In the previous articles, we saw Single-Call Remote Object and Singleton Remote Object. In this article, we will explore the usage of Generic Interface in the Remote Objects. First, we will explore how the server will register it and then move on to the client which consumes it. First, we will implement the server. One can read the base article given in the link below to know the basics of ‘Dotnet Remoting’:

Dotnet Remoting Single-call and Basics

Search Tags For this Article: Search the below tags in the downloaded application to know the Sequence of code changes for this article:

  • //Server 0
  • //Client 0

Start a Visual C# console project called ‘GenRemSrv’. Once the project is set up, add a generic interface. Our remote object will implement this interface. Below is the code:

namespace GenRemSrv
{
    //Server 001: Generic Interface which has only one 
    //method takes and generic type and return same kind 
    //of generic type
    public interface IGenericIface<T>
    {
        void AddData(T Data);
        string GetData();
    }
}

Note the usage of the Letter T. It can be substituted by any data type. In our example, we will use this interface for int and string data types. But one can use it for any data type. Therefore, the interface is called ‘Generic Interface’.

2. Remote Class Implementing Generic Interface

In this section, we will define our Remote Class. Also, this Remote Class will implement our Generic Interface.

2.1 Remote Class with T

Next, we add a new class to the ‘GenRemSrv’ Project and Name it as InputKeeper<T>. Here, once again the T stands for any data type. Also, note how the generic interface is inherited here by specifying the T substitution. The InputKeeper is our remote class. Below is the code:

//Server 002: Public class that implements 
//MarshalbyRef and the Generic interface
public class InputKeeper<T> : MarshalByRefObject, 
    IGenericIface<int> , 
    IGenericIface<string>
{

2.2 Remote Variables

Next, we declare two variables in our remote class to store a string and an integer value. In the constructor, we initialize these variables to a default value. Later, our client will change these values through remote function call.

//Server 003: Variable declaration
int CollectedInt;
string CollectedString;
 
//Server 004: Constructor 
public InputKeeper()
{
    CollectedInt = 0;
    CollectedString = "";
    System.Console.WriteLine(
        "Input Keeper Constructoed");
}

2.3 Implement Generic Interface on Remote Class

Finally, we implement the Generic Interface functions as below. In the below code, we derive our remote class InputKeeper from two contracts, ‘IGenericIface<int>‘ and ‘IGenericIface<string>‘. This will force us to write the AddData function two times. The first version takes an integer as an argument and the second version takes a string as an argument. Since, GetData is not a template function, we implement it once. We can look at our Generic Interface once again. The GetData returns a string not T.

//Server 005: Implement the Interface Function
public void AddData(int Data)
{
    CollectedInt = CollectedInt + Data;
}
 
public void AddData(string Data)
{
    CollectedString = CollectedString + 
        ", " + Data;
}
 
public string GetData()
{
    string str = String.Format(
    "Collected integer sum {0},"  +
    "Collected String : {1}", 
    CollectedInt, CollectedString);
    return str;            
}

3. Registering Remote Object

I hope you read our first article specified in the introduction section. This article will not explain the basics of remoting as it is already explained in the first article on ‘Remoting’.

As our remote object itself a generic object (‘InputKeeper<T>‘), we need to register the object resolving the type T. In our case; we have two different remote objects for handling integer and string types. The below code will register our ‘InputKeeper’ for both the data types.

static void Main(string[] args)
{
    //Server 007: Register the TCP channel with 
    //port number 14750
    TcpServerChannel port = new
        TcpServerChannel(14750);
    ChannelServices.RegisterChannel(port, false);
 
    //Server 008: Register the remote objects. 
    //Note the generic is split based on the 
    //type usage
    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(InputKeeper<int>), 
        "IntKeeper", WellKnownObjectMode.Singleton );
    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(InputKeeper<string>),
        "StringKeeper", WellKnownObjectMode.Singleton);
 
    //Server 009: Some indication that 
    //server is started
    Console.WriteLine("Server Started. Int Keeper" +
        "and String Keepers are ready..");
    Console.WriteLine("Press Any key to " +
        "Halt the Server");
    Console.ReadLine();

4. Client Accessing Generic Remote Interface

To set up a client application, we need to add a new Visual C# Windows Application. We should use the ‘File, Add New’ project without closing the server project. This will keep both the project under single solution. While making the application name the project as Generic User. Next, one can design the form as shown below. Otherwise, use the downloaded application as the reference.

Remoting Genric Interface Client Application Design

Remoting Generic Interface Client Application Design

The first send button on the left side will contact the Generic Remote Object for integer and second send button will contact the Generic Remote Object for the string. We will display the data collected on the list box. Also note, we registered two Generic Objects on the server’s Remote Pool. They are independent. We can enter an integer value on the left text box and click the send button multiple times. We can do the same for the string. On the server, integer values and string values are persisted by their dedicated remote objects. Note, both the objects remember the data collected in the previous session (Send button click) as it was registered as ‘Singleton’. OK. Let us start the implementation.

4.1 Remoting Reference

First, we should add a reference for Remoting run times and the reference to our server project. You can refer the previous article which is given in the introduction section. Include the following Namespace for the form code:

//Client 001: Namespace inclution 
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Channels; 

//For Communication Method 
using System.Runtime.Remoting.Channels.Tcp; 

//Refers our Server 
using GenRemSrv;

4.2 Resolving Generic Interface Types

Next, we declare two generic interfaces. One interface is for referring the integer Remote Object and the other one is for string. The left send button will use integer interface and right send button will use string interface. Note, how the Template T on the generic interface is resolved by substituting it with valid data types.

//Client 002: Object declaration using the 
//generic types
private IGenericIface<int> intObject;
private IGenericIface<string> stringObject;

4.3 Proxy to Remote Objects

In the form load event handler, after saying the transmission channel, the remote objects which implement the Generic Interface are retrieved (Proxy) and stored in the interface class members declared in the past step. Note, how we resolve the Generic Interface by pointing out the type through type casting.

private void frmUser_Load(object sender, EventArgs e)
{
    //Client 003: Register the Communication channel
    ChannelServices.RegisterChannel(new TcpClientChannel(),
        false);
 
    //Client 004: Get the generic remote object of int 
    //type and string type
    intObject = (IGenericIface<int>) 
        Activator.GetObject(typeof(IGenericIface<int>),
        "Tcp://localhost:14750/IntKeeper");
    stringObject = (IGenericIface<string>) 
        Activator.GetObject(typeof(IGenericIface<string>),
        "Tcp://localhost:14750/StringKeeper"); 
}

4.4 Sending Integer and String to Remote Server

The left and right Send Button will make a call to the relevant Remote Objects. Remember, the function exposed by our Remote Generic Interface is ‘AddData’ and ‘GetData’. On the Server, the ‘AddData’ for integer performs the summation of supplied integer and ‘AddData’ for the string will append the input string. Below is the code for the Send Button click handlers:

//Client 005: Parse the data entered in the integer 
//input and send it to the remote object
private void btnSend1_Click(object sender, EventArgs e)
{
    int input;
    if (int.TryParse(txtInt.Text, out input) == true)
    {
        intObject.AddData(input);
    }
 
    txtOutput.Text = intObject.GetData();
}
 
//Client 006: send the string data to the remote object
private void btnSend2_Click(object sender, EventArgs e)
{
    stringObject.AddData(txtString.Text);
    txtOutput.Text = stringObject.GetData();
}

5. Running the Example

Follow the steps below to run and test the application:

  1. First Execute the server
  2. Launch Client Application
  3. Enter 7 in the Left Input Box, click the Send Button
  4. Enter 3 in the Left Input Box, click Send Button
  5. Type ‘One’ in the Right Input Box, click the Send Button
  6. Type ‘Two’ in the Right Input Box, click the Send Button

The output of the above test is given in the below picture:

Running the Generic Remote Interface Example

Running the Generic Remote Interface Example

Source Code: Download Generic Interface Example from Google Drive

Categories: Remoting

Tags: , ,

Do you like this Example? Share your thoughts!!

This site uses Akismet to reduce spam. Learn how your comment data is processed.