Sunday, March 06, 2011

.Net Remoting - Singleton Generic Interface, Server activated

1. Introduction


In the previous articles, you saw Singlecall remote object and Singleton remote object. In this article I will show you the usage of Generics in the remote object and how the server will register it and how the client will consume it. For the previous articles, select the remoting section from the sidebar and navigate. You will the good articles on this topic from other authors also.

Let us first begin with a server. I suggest, you can first read the basic article from the remoting label. It will be easy to understand this article once you know the basics.

Search Tags: Search the below tags in the downloaded application to know the Sequence of code changes.

//Server 0
//Client 0

2. The Generic Interface


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

//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 indicates that the function accepts any data type. In our example, we are going to use this interface for int as well as string data types.

3. Remote Class using Generic Interface


Add a new class to the GenRemSrv Project and Name it InputKeeper<T>. Here, once again the T stands for some data type.  Also, note how the generic interface is inherited here by specifying the T substitution. Below is the code:

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

Next the constructor and the variables required for this coded. Below is the code for that:

//Server 003: Variable declaration
int CollectedInt;
string CollectedString;

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

Finally, the interface functions are implemented as shown below:

//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;           
}

In the above code, not that the Adddata function is implemented twice one using the int data type and another one is using the string data type. As we derived the class from the generic interface that supports both the data types int and string (IGenericIface<int>IGenericIface<string>) it becomes necessary to implement the interface generic function void AddData(T Data); twice by substituting the required data types.

4. Hosting the remote objects


I hope you read my first article. I am not going to explain everything, which I 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 are using two different types integer and string and so we need two registrations. The below code register the InputKeeper for both the data types on the TCP channel identified by the port 14750.

//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();

5. The client application


Add a new visual C# windows application and Name the project as Generic User. Use the File, add new project without closing the server project so that both the project is available for a solution. The form design is shown below:

Generic Interface - Example
Fig 1. Generic Interface - Example


The first send button will contact the generic remote object for integer and second send button will contact the generic remote object for the string. The data collected so for will be displayed on the multi-select list box. Also, note that we have two generic objects on the server’s remote pool and they are independent. Enter some integer on the left group box and click the send button and type some other integer click the send button again. Do the same for the string also. This is just for the test and data is persisted on each object in their contexts we registered the object as a singleton.

Provide the reference for Remoting runtime and the server project as we already did in our first dot net remoting project. The reference to that article is given in the introduction section.

1) Include the following Namespace for the form code:

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

2) Client declared generic interfaces. One interface is for integer and the other one is a string. The integer interface is used by the left send button click and right send button will use string interface.

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

3) In the form load event handler, after registering the communication channel, the remote objects are retrieved (Proxy) and stored in the interface class members declared in the previous step.

//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) The left and right send button will make a call to the relevant remote object (Generic object). Remember, the function exposed by our remote generic interface is AddData and GetData. The AddData for integer simply performs the summation of supplied integer and AddData for the string will simply append the given string input. Note that the proper simplicity I collected the data in string and integer variables in the server. Collecting the input in a variable of Type T should do the proper implementation.  For simplicity, I used CollectedInt and CollectedString. However, I hope this will explain how to use generic remote objects in remoting environment. 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();
}

Running the application is shown below:

 Running the application
Fig 2. Running the application


Source Code : Download

Note: The attached solution is created in VS2005. If you have the latest version say yes to the conversion UI displayed.

No comments:

Post a Comment

Leave your comment(s) here.

Like this site? Tell it to your Firend :)