Working with Remote Objects in C#

This article shows how to create a remote server and MDI window Remote Client using remote object. The remote server can be used as Auction Server and Real Time Data and Information Server.

.NET Remoting is a technology that can be used to allow .NET applications to communicate to each other, it is does not matter to cross a network with firewall security, or over the Internet. The Remote object can be used to transport messages between remote objects using different transportation protocols, serialization formats, and object lifetime schemes.

An object derived from MarshalByRefObject can be used as Remotable objects. Remotable objects can be accessed by other application domain using a proxy or they can be passed to another application domain by value or by reference.

In this article, the clients register their callback by passing their object to the server. This way let the server control the client easier than the way that registers callback using delegate and event (See my article Remote Object Part1). In this way, it is much easier for the server to handle the registration and the situation that the clients closed without call the server's unregister function.

RebObj2server.jpg

Figure 1. Channel Server

RebObj2Client1.jpg

Figure 2. Client Host

RebObj2client2.jpg

Figure 3. Client Host.

RebObj2pusher.jpg

Figure 4.

The program includes three parts.

  1. Window Server with a remote object that supports Auction, News, Market News, Real time Stocks Data. (See Fig 1)
  2. MDI Window Client with a remote object that used to register user to the remote server and display the information that is coming from the server. (See Fig 2, 3)
  3. Pusher can be used to send all kind of information to sever then the server send all the information to the registered users. (See Fig 4)

Client Host:

The client open a remote channel and pass their remote objects to the server to register their callback function and keep a cookie to cleanup the register when the client is closed. This gives the remote server more flexibility and more control to the clients than the method described in the Remote Object Part1.

public void ConnctServer()
{
HttpChannel chan =
new HttpChannel(Int32.Parse(MyDlg.port));
ChannelServices.RegisterChannel(chan);
SrvObj = (RemoteServer)Activator.GetObject(
typeof(WRemoteServer.RemoteServer),
http://localhost:8085/RemoteObj);
if (SrvObj == null)
lb.Items.Add("Can't connect to server");
else
registerClient(MyDlg);
}
private void registerClient(Login MyDlg)
{
RemotingConfiguration.RegisterWellKnownServiceType(
Type.GetType("WRemoteClient.RemotingClient,
RemotingClient"),
"ClientObj",
WellKnownObjectMode.Singleton);
string url=String.Format("http://localhost:{0}/
ClientObj", MyDlg.port);
CltObj = (RemotingClient)Activator.GetObject(
typeof(WRemoteClient.RemotingClient),
url);
string rtnMsg;
Cookie = SrvObj.SinkClientObj(CltObj, MyDlg.srvType,
MyDlg.username, MyDlg.password,
out rtnMsg);
CltObj.InvokeFormMethod +=
new
CFormEventHandler(OnMsgHandler);
lb.Items.Add(MyDlg.username + ":" + MyDlg.srvType+" register is "
+ rtnMsg);
}

Client Remote Object:

This object is small and only used to handle the callback from the Remote server. Passing it as value to Remote object is acceptable.

namespace
WremoteClient
{
public delegate void CFormEventHandler(object sender, RemoteEventArgs e);
public class RemotingClient : MarshalByRefObject
{
public event CFormEventHandler InvokeFormMethod;
[OneWay]
public void ClientReciever(string msg, string newsTitle,
string newsContents, int type)
{
RemoteEventArgs e =
new RemoteEventArgs(msg,"","",
newsTitle, newsContents, type);
if(InvokeFormMethod != null)
InvokeFormMethod(
this, e);
}
}
}

Server Host:

private void startServer()
{
ChannelServices.RegisterChannel(
new HttpChannel(8085));
RemotingConfiguration.RegisterWellKnownServiceType(
Type.GetType("WRemoteServer.RemoteServer,RemoteServer"),
"RemoteObj", WellKnownObjectMode.SingleCall);
SrvActObj = (RemoteServer)Activator.GetObject(
typeof(WRemoteServer.RemoteServer),
http://localhost:8085/RemoteObj);
SrvActObj.CreateUsrInfo();
usrGrid.DataSource = RemoteServer.usrMgrTab;
}

Server Remote Object:

This object supports four function, Auction, Real-Time Stock information , News and Market News. It includes four SortedList to hold the registered client object that is used to callback when the data is available. This makes the server to call the methods of the clients and to pass a more complex data type to the clients every easy. The proxy automatically converts all kind of data type between the call.

The client can register their request by call the function SinkClientObj() and call UnSinkObj() to clean the register on the server.

namespace
WremoteServer
{
// Define the event
public delegate void ServerEventHandler (object sender,
RemoteEventArgs e);
public class RemoteServer : MarshalByRefObject
{
public static event ServerEventHandler InvokeHostForm;
private static SortedList StockObjHolder = new SortedList();
private static SortedList NewsObjHolder = new SortedList();
private static SortedList AuctionObjHolder = new SortedList();
private static SortedList MarketObjHolder = new SortedList();
public static DataTable usrMgrTab = new DataTable("UsrMgr");
public string SinkClientObj(Object obj, string srvType,
string username, string password, out string rtnMsg)
{
bool chkStatus=false;
chkStatus = CheckUser(username, password, srvType);
if(chkStatus)
{
rtnMsg = "Ok";
switch(srvType)
{
case "Stock":
lock(this)
{
if(!StockObjHolder.ContainsKey(username))
StockObjHolder.Add(username,
(RemotingClient) obj);
else
{
StockObjHolder[username] =
(RemotingClient) obj;
rtnMsg = "Ok But it replace
previous registerd one!";
}
}
break;
case "News":
lock(this)
{
if(!NewsObjHolder.ContainsKey(username))
NewsObjHolder.Add(username,
(RemotingClient) obj);
else
{
NewsObjHolder[username] =
(RemotingClient) obj;
rtnMsg = "Ok But it replace
previous registerd one!";
}
}
break;
case "Auction":
lock(this)
{
if(!AuctionObjHolder.ContainsKey(username))
AuctionObjHolder.Add(username,
(RemotingClient) obj);
else
{
AuctionObjHolder[username] =
(RemotingClient) obj;
rtnMsg = "Ok But it replace
previous registerd one!";
}
}
break;
case "Market News":
lock(this)
{
if(!MarketObjHolder.ContainsKey(username))
MarketObjHolder.Add(username,
(RemotingClient) obj);
else
{
MarketObjHolder[username] =
(RemotingClient) obj;
rtnMsg = "Ok But it replace
previous registerd one!";
}
}
break;
}
RemoteEventArgs e =
new RemoteEventArgs(rtnMsg,
username, srvType, "", "",0);
// Fire server form event
if(InvokeHostForm != null)
InvokeHostForm(
this, e);
}
else
rtnMsg = "Fail";
return username;
}
public void UnSinkObj(string Cookie, string serType, bool client)
{
if(client)
{
if(srvType == "")
{
StockObjHolder.Remove(Cookie);
NewsObjHolder.Remove(Cookie);
AuctionObjHolder.Remove(Cookie);
MarketObjHolder.Remove(Cookie);
}
else
{
switch(srvType)
{
case "Stock":
StockObjHolder.Remove(Cookie);
break;
case "News":
NewsObjHolder.Remove(Cookie);
break;
case "Auction":
AuctionObjHolder.Remove(Cookie);
break;
case "Market News":
MarketObjHolder.Remove(Cookie);
break;
}
}
string tmp =string.Format("{0} is unregistered!", Cookie);
RemoteEventArgs e =
new RemoteEventArgs(tmp, "", "", "",
"",0);
// Fire server form event
if(InvokeHostForm != null)
InvokeHostForm(
this, e);
}
public void SendMsgToClient(int msgType, string title, string
contents,
string msg)
{
RemoteEventArgs e =
new RemoteEventArgs("", "", "", title,
contents,0);
string removeKey="no";
switch(msgType)
{
case 1:
foreach(string key in NewsObjHolder.Keys)
{
try
{
clientObj =
(RemotingClient)NewsObjHolder[key];
clientObj.ClientReciever("", title,
contents, msgType);
}
catch { removeKey = key;}
}
break;
case 2:
foreach(string key in MarketObjHolder.Keys
{
try
{
clientObj =
(RemotingClient)MarketObjHolder[key];
clientObj.ClientReciever("", title,
contents, msgType);
}
catch { removeKey = key;}
}
break;
case 3:
foreach(string key in AuctionObjHolder.Keys)
{
try
{
clientObj =
(RemotingClient)AuctionObjHolder[key];
clientObj.ClientReciever("", title,
contents, msgType);
}
catch { removeKey = key;}
}
break;
case 4:
foreach(RemotingClient rc in NewsObjHolder.Values)
rc.ClientReciever(msg, "", "", msgType);
foreach(RemotingClient rc in StockObjHolder.Values)
rc.ClientReciever(msg, "", "", msgType);
foreach(RemotingClient rc in AuctionObjHolder.Values)
rc.ClientReciever(msg, "", "", msgType);
foreach(RemotingClient rc in MarketObjHolder.Values)
rc.ClientReciever(msg, "", "", msgType);
break;
}
if(removeKey != "no")
{
// Remove the register that cause the exception
NewsObjHolder.Remove(removeKey);
RemoteEventArgs e2 =
new RemoteEventArgs(removeKey +
" is removed!", "", "", "", "",0);
// Fire server form event
if(InvokeHostForm != null)
InvokeHostForm(
this, e2);
}
}
... ... ...
}

Steps to create the sample:

  1. Compile the Remote object by running makefile.bat at RemoteObj directory.
  2. Compile the WremoteClient , the WremoteServer and the InfoPusher. You may need to change the references to these DLL.
  3. Copy all the DLL files in RemoteObj directory to the ..\bin\Debug directory.

Guide to use all the function that the server supplied:

  • Start all three programs (may start more than one clients). The server shows there are three registered users (user1, user2 and user3) who can request different function on this server.
  • Connect to server on Pusher. Now you are ready to send all information to registered clients. (See Fig 4).
  • Click Register on the client. A dialog is opened for you to select what kind service does you wanted from server by now.
  • If the Stock is selected, a child form appear, you can click the button Send real-time stock data on the server to get real time data from a file (Dont missing Issue.txt in Debug Directory). (See Fig 3)
  • If Auction is selected, a Go to Auction button appears. Click it to bid your items. All the data will be showed in the ListBox (See Fig 2)
  • If news is selected, the client host child form can only display 5 titles of the news. The oldest one will be removed. Click the title of the news, a child form appears, that displays the contents of the news (See Fig 2).

Conclusion

.Net Remoting the most advantage technology that could be used in the client/server application than the others. Remoting is very flexible, powerful and easy to program with TCP, HTTP and SOAP. (Compare with DCOM).


Similar Articles