Monday, December 27, 2010

[ Dot Net Remoting ] - Single Call server activated Remote Object

1. Introduction


Dot net remoting is client and server based distributed object technology. In this first article about dot net remoting, we will create two applications. One is a remote server application and another one is a client application. We will go ahead and start creating the applications and I will give the explanation when we are developing the example.

2. About this Example


The server we are going to create is a console application. This console application will host our remote objects on the server. The client will make a call to the public members (Usually function) exposed by that remote object(s).

The client is a windows form application, which will get access to the remotely hosted objects and start using it. Below is the screen shot of the client application.

Net Remorting - Serialisation Example
Fig 1. .Net Remorting - Serialisation Example


When we click the Get Details button, the client makes a call to the remote server console application to get the Customer Id, Customer Name, Last Deposit and Last Withdraw from the remote object LastTrans. I will explain other concepts when we move along.

First, we will go ahead and start our Remote server console application.

3. Remote Server Console App


1) Create a new console application and name it ConServer.
2) Right click the ConServer project and choose Add reference
3) From the dialog displayed Select "System.Runtime.Remoting" from the .net tab and click the OK button. This step provides access to the dot net remoting API.
4) Next, add a class named LastTrans to the Project. Add one more class and name it as RemCustomer.

Explanation

We have created a console application project and then got access to the dot net remoting assemblies. Then we added classes to the project. RemoteObject is the one which will keep in the Server’s memory. And LastTrans object is created on the server but it will be sent to the client through serialisation using the RemoteObject.

"Serialisation" is a technique, which converts your class in the form of "bit streams" and these steam in the receiving end is collected to form the actual object. In our example, we are going to send the LastTrans to the client through serialisation .

All the skeleton code for our server is kept ready by the IDE. Now we will go ahead and add code.

4. The LastTrans Class


1) Locate the LastTrans class created by the IDE and Mark it as "Serializable" by adding the serializable attribute before the class. Below is the code for it:

//RemoteServer_018: Make the Class Serializable
[Serializable()]
public class LastTrans

2) Add a private variable to this class.

//RemoteServer_011: Private field for the Newly added class
private int LastDeposit;
private int LastWithdraw;

3) In the constructor initialize the above declared private variables. Note that here I hard-coded the values. In the real world, it will be queried from the database to get the latest result. Below is the code:

//RemoteServer_012: Constructor for Last Transactions. At present we will
//Default it to some constant value
public LastTrans()
{
    //Hard Coded here. In real world make a query to the Database to get
    //the latest information.
    LastDeposit = 68800;
    LastWithdraw = 12000;
}

4) Next, provide a function to return the private variables. The client uses these functions to get the Last Deposit amount and as well as Last Withdrawal amount.

//RemoteServer_013: Get the Last Transaction amount
public int GetLastDeposit()
{
    Console.WriteLine("Last deposit Queried...");
    return LastDeposit;
}

public int GetLastWithdraw()
{
    Console.WriteLine("Last Withdrawl amount Queried...");
    return LastWithdraw;
}

Note that the console.WriteLine does not print anything on our Remote Server. Because the object is serialised and sent to a client. The client creates this object and subsequent call on the object gets executed on the client machine.

5. The RemCustomer Class


1) Include the below-specified namespace.

//Remote_003: Include the Namespace
using System.Runtime;

2) This class acts as the remote object. To make the IDE created object remote server compatible, (Refer Step 4) locate the class and derive it from the "MarshalByrefObject". OK. Why that derivation is required. It is required as we are planning to keep this object in server’s remote pool. Below is the Second step of the code:

//RemoteServer_004: Make the class Remotable by inheritance.
public class RemCustomer : System.MarshalByRefObject

3) Next, declare the members of this class. Note our remote object is going to serve the client through standard as well as user-defined data types. User-defined type here in our case is the LastTrans which you already saw that we marked it as serializable.

//RemoteServer_005: Feilds on the remote Class
private string CustName;
private int CustId;
//RemoteServer_014: Instance for LastTrans declared
private LastTrans trans;

4) The constructor will initialize the members declared. Constructor is below:

//RemoteServer_006: Constructor for the Remote Object
public RemCustomer()
{
    CustName = "Ram Gopal";
    CustId = 1235;
    Console.WriteLine("Instance of Remote object Created...");

    //RemoteServer_015: Instance for LastTrans created
    trans = new LastTrans();
    Console.WriteLine("Instance of Last Transaction object created. ");
}

5) Other member functions are shown below. These can be easily understandable.

//RemoteServer_007: Get the Customer id
public int Get_id()
{
    Console.WriteLine("Customer Id requested...");
    return CustId;
}

//RemoteServer_008: Get the Customer Name
public string Get_Name()
{
    Console.WriteLine("Customer Name requested...");
    return CustName;
}

//RemoteServer_017: Instance for LastTrans declared
public LastTrans GetLastTrans()
{
    Console.WriteLine("Transaction object requested...");
    return trans;
}

Now our remote class also ready to serve the windows form based client. Note that the MarshalByrefObject states that this RemCustomer will reside on the server and a reference to it will be sent to the client. The client calls that reference as a "proxy". We will move to our last step, which is the program entry point of a console application.

6. Hosting the Remote Object on the Server


1) Locate the static void main, which is the program entry point for the console application. In the top of the file (Program.cs if you had not changed the file name) include the assemblies as shown. Below is the code:

//RemoteServer_001: Required Assemblies
using System.Runtime;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

2) Next, a "TCP channel" with a "port number" 13340 is created and registered in the server machine. The client application will use this port to communicate with the remote object. The below code creates a TCP communication channel and registers that with the server machine in which the server application is going to run.

//RemoteServer_002: Create a communication channel (Server) and register it
TcpServerChannel SrvrChnl = new TcpServerChannel(13340);
ChannelServices.RegisterChannel(SrvrChnl, false);

3) Once the communication method is specified it is time to register our remote object on the server machine. The first parameter to the function specifies the type of the object that is registered. The second one gives a unique name for the registered object. I do keep the registration name same as the class name. But, you can use a different name. The client should use the same name when they ask for the Proxy of the remote object. The third parameter says how the server should activate the remote object. In this example, we are using the "Single Call method". That means for each client call an object will be created and maintained in the pool.

We will look at singleton method in next article.

//RemoteServer_009: Register the Remote Class so that the Object can go
//and sit on the Remote pool
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ConServer.RemCustomer), "RemCustomer", WellKnownObjectMode.SingleCall);

4) The server is ready. Break the execution using the ReadKey method.

//RemoteServer_010: Halt the server so that Remote client can access the object
Console.WriteLine("Server is Running...");
Console.WriteLine("Press Any key to halt the Server");
Console.ReadKey();

If you want you can run the server now. But, there is nobody to consume the registered remote object on your server. We will now move on creating the Client. Below is screen shot:

 Remote Server session
Fig 2. Remote Server session


Note: The remote object is not created as the activation method is SingleCall. For each client call, a separate instance of the remCustomer will be created and kept in the remote object pool.

7. Prepare the Client Application


As you already know a client is a Windows form application. Follow the steps below to create the client application that uses the remote object hosted by our console server.

Make sure the Console server project is still in open state.

  1. Click on File|Add|New Project.
  2. Select Visual C# in the project Types and Select Windows Application from the available template.
  3. Name the project as RemClient and click ok.
  4. Design your form by referring the first screen shot. Download the attached project for your reference and set the properties by referring it. ConServer.sln will open both the project. In your case, this solution will be created now as you are adding one more project. A solution file is a combination two or more projects.
  5. Add reference for Remoting assembly as you did in the server step 3.
  6. Once your form is designed, double click the Button control to get the Click event handler for it.
  7. Right click the RemClient Project and select add reference. Go to the project tab and select ConServer Project.

Explanation

In the above steps, you created a windows application and designed the form. You added a reference to the Dot net’s Remoting assembly and added a reference to the ConServer application. If we use the interfaces we can avoid this project reference. We will see that in a separate article.


8. Start coding the client


1) First, include the below-specified Name Spaces on top of the file which has the click event handler for the button. The code is below:

//RemoteClient_001: Include the required namespace
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using ConServer;


2) Now we will implement the click event handler. The button click will invoke the public functions exposed by the Remote object. Make sure the RemCustomer on your server application is Public. The first step is to get the Proxy for the remote object hosted by the Console Application, which runs on the Local or Remote machine. Below is the code for doing that:

//RemoteClient_002: Get the remote object on the server
RemCustomer remoteCust = (RemCustomer)Activator.GetObject(typeof(RemCustomer), "tcp://localhost:13340/RemCustomer");

In the first parameter, we specified what object we are looking for. In our case, it is the actual object type. The project reference we added is just to resolve this type (RemCustomer) name. But, in the interface approach, it is not required to reference the server project. Just an interface type is required on both server and client. If the client develops the application to invoke the third party remote server object then the server developers usually provide the interface. By doing that the server piece of implementation not revealed to the client developers. In our case, let us assume the same party develops server and the client.

The Second string parameter has three parts on it. The first one is machine name. As the client and server applications are on the same machine, I kept localhost instead of specifying the machine name. If the Server application is running on the machine name say; C-AshCorner_01 then the localhost in the string should be replaced by the machine name; that is; C-AshCorner_01. Note one can also use the IP address of that machine.

Well. The client now knows which machine it need make a connection to get the RemCustomer proxy. But the server may have lot of network communication right? It may be an Oracle server or Sql2005 server or even a Jboss web server. How does the server make communication? That is why we registered the server with a port number 13340. This port on TCP communication is called "Dedicated Port". Oracle has its dedicated port. Jboss has it an own dedicated port. Our application server registered the port 13340 saying “This port is in use like 80 for HTTP”.

Our client application by specifying this port number next to the machine name, sets-up the communication for a connection request. The last part specifies the registered name of the remote object. Look at Section 6 point 3.

Finally, we performed a type cast and stored the proxy in the remoteCust.

In summary to get the remote object,
1) First, a machine name in the network needs to be resolved
2) A port number that specifies which particular Server Application needs to be contacted.
3) The registered name specifies a single object type upon several registered remote objects (We registered only one)

3) Once the proxy is with us, make a call to the functions through a proxy. Note proxy just shows that the object is with you, but it is not. All the call is transmitted to the server to get the result. Below is the code, which makes use of the proxy object to make a call on the public functions, exposed by the remote object remCutomer.

//RemoteClient_003: Get Customer Id and Name exposed by the remote object itself
int id = remoteCust.Get_id();
string name = remoteCust.Get_Name();

//RemoteClient_004: Get Some other object from the server through the remote
//object. Note the object should be serializable.
LastTrans trans = remoteCust.GetLastTrans();
int lastdeposit = trans.GetLastDeposit();
int lastwithdraw = trans.GetLastWithdraw();

//RemoteClient_005: Display the information retrieved
txtCustId.Text  = id.ToString();
txtCustName.Text  = name;
txtLastDeposit.Text = lastdeposit.ToString();
txtLastWithdraw.Text = lastwithdraw.ToString();
btnInvokeRemote.Enabled = false;

The picture below explains how the application will work.




9. Testing the Application


Test it on Same Machine
1) Right click the solution and Click rebuild all.
2) Now navigate to both the exe using windows explore.
3) Run the Console Server
4) Run the Windows application
5) Click the button on the Windows application and Observe the result on the Client.

To Test it on different Machine, Place the Server project on the different machine. Keep the Client on your machine. Search for localhost in the client project and replace it with your machine name or IP Address. Run the Server first and then the client.

Below is the screen shot when Run both the application in the same machine.



10. Closing Note


1) To see the result live, download the Screen cam: Download
2) To know how to debug, download and see the Steps: Download

Source Code : Download

2 comments:

  1. excepting more articles...

    your work is great in C-sharpcorner.com.

    excepting more articles.

    ReplyDelete
  2. Thankyou for such a good article,helping me a lot.

    ReplyDelete

Leave your comment(s) here.

Like this site? Tell it to your Firend :)