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:
1 2 3 4 5 6 7 8 9 10 11 |
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:
1 2 3 4 5 6 |
//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.
1 2 3 4 5 6 7 8 9 10 11 12 |
//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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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 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:
1 2 3 4 5 6 7 8 9 |
//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.
1 2 3 4 |
//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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//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:
- First Execute the server
- Launch Client Application
- Enter 7 in the Left Input Box, click the Send Button
- Enter 3 in the Left Input Box, click Send Button
- Type ‘One’ in the Right Input Box, click the Send Button
- 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
Source Code: Download Generic Interface Example from Google Drive
Categories: Remoting
Tags: C# Remote Template Object, C# Remoting Generic Interface, C# Singleton Remoting