hostserver.exe.config
this is a configuration file to config the remoting objecta and objectx on the tcp channel port# 12345. both objects have been choose for server activatation running as a wellknown object in the singlecall mode. this config file can be modified during the deploying process to match an application environment.
<configuration>
<system.runtime.remoting>
<application name="remotetest">
<service>
<wellknown mode="singlecall" type="rkiss.remoteobjecta.rmobjecta, remoteobjecta" objecturi="objecta" />
</service>
<service>
<wellknown mode="singlecall" type="rkiss.remoteobjectx.rmobjectx, remoteobjectx" objecturi="objectx" />
</service>
<channels>
<channel type="system.runtime.remoting.channels.tcp.tcpchannel, system.runtime.remoting" port="12345" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
remotewindowsform
this is a client side – consumer of the remoting objects. the remoting client can be any object on the enterprise network. this sample is using a windows form to demonstrate an asynchronously invoking remote objects with callbacks to the windows controls.
there are 3 major parts on the client side related to the remoting callbacks:
initialization
the initialization part has the following responsibility for the remoting process and connectivity:
subscribing (config) a callback object as a remoting object
creating proxy objects of the requested remote objects based on the configuration file
making an echo test on the remoting objects
the following code snippet shows that:
public form1()
{
initializecomponent();
try
{
sub = new remotecallbacksubscriber(this);
cb.parent = this; // we need an access to the parent properties
// get the remoting uriaddress
namevaluecollection uriaddr = (namevaluecollection)configurationsettings.getconfig("client/urladdress");
string uriobjecta = (string)uriaddr["objecta"];
string uriobjectx = (string)uriaddr["objectx"];
string uriobjectws = (string)uriaddr["objectws"];
// type of the remote interface
type typeofri = typeof(rkiss.remoteobject.irmobject);
// create a proxy of the remote objects
roa = (irmobject)activator.getobject(typeofri, uriobjecta);
rox = (irmobject)activator.getobject(typeofri, uriobjectx);
rows = (irmobject)activator.getobject(typeofri, uriobjectws);
//
// (sub["cb"] as tcpchannel).startlistening(0); // sample how to control a tcp channel
// echo test
textboxstatus.text = rows.echo(roa.echo(rox.echo("this is an echo message")));
}
catch(exception ex)
{
textboxstatus.text = ex.message;
buttonrm.hide();
}
}
callback object
the callback object is the remoting object for the clients remoting objects, thats why it is derived from the marshalbyrefobject class. the callback object has been initiated for infinity lease time (actually its life time is depended from the clients life time). there is one callback method – progress with the arguments (state) passed from the remote object. based on this state, the dispatchevent helper calls a particular windows control. note that callback method is running in the "fire&forget" fashion to isolated processes and minimize its respond time. the callback object holding a state of the progressing and passing back to the remote object which it will allow to abort the remoting call. this a a great feature of the remoting callbacks to make the remote call pre-emptive.
// ———–< callback class >——————————————-
public class callbackclass : marshalbyrefobject
{
private form1 _parent = null;
private bool _state = false;
public form1 parent { set { _parent = value; }}
public bool state { set { lock(this) { _state = value; }}}
// set a leaseing time for infinity
public override object initializelifetimeservice()
{
ilease lease = (ilease)base.initializelifetimeservice();
if(lease.currentstate == leasestate.initial)
{
lease.initialleasetime = timespan.fromminutes(0);
}
return lease;
}
//
// callbackmethod
public bool progress(string sender, object e)
{
// fire&forget
threadpool.queueuserworkitem(new waitcallback(dispatchevent), e);
return _state;
}
// helper
private void dispatchevent(object e)
{
callbackeventargs cea = e as callbackeventargs;
// a simple work with the parents control
lock(this)
{
if(cea.ticketid == "progressbar")
{
if(cea.state is int)
{
_parent.textboxstatus.text = cea.state.tostring();
_parent.progressbarstatus.performstep();
}
else
if(cea.state is string)
_parent.textboxstatus.text = cea.state.tostring();
}
else
if(cea.ticketid == "textbox")
{
if(_parent.textboxstatus.backcolor == color.yellow)
_parent.textboxstatus.backcolor = color.white;
else
_parent.textboxstatus.backcolor = color.yellow;
}
else
if(cea.ticketid == "button")
{
if(_parent.buttonrm.forecolor == color.magenta)
_parent.buttonrm.forecolor = color.black;
else
_parent.buttonrm.forecolor = color.magenta;
}
}
}
} // end of the callbackclass
