Click to See Complete Forum and Search --> : C# .NET Remoting


jdkulkarni
June 20th, 2005, 02:49 AM
Can anybody tell me that, if i'm using .NET remoting server with SAO, how can i raise an event across different application domains? the application wors fine when on the same machine but creates problem when I try using server and client on different machine.
The error description and stack trace is:
I tried with microsoft solution which says that u create an abstract class and override it in client and handle events there. But it does not work for me.

Here is the error:
Exception occured at server. Message:
Server encountered an internal error. For more information, turn on customError
s in the server's .config file.
Stack trace:

Server stack trace:


Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req
Msg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgDa
ta, Int32 type)
at Coordinator.RemotableDelegate.WelComeMessage(ChatArgs ca) in E:\Jayant\Pra
ctice\MyChatArchitecture\Coordinator\IMediator.cs:line 139
at MarshalByRefClass.Mediator.ConnectMe(String userName) in E:\Jayant\Practic
e\MyChatArchitecture\MarshalByRefClass\Mediator.cs:line 49



I'm not using any App.config file. My server code is as follows.

// For Http channel
try
{
SoapClientFormatterSinkProvider scl = null;
SoapServerFormatterSinkProvider ssr = new SoapServerFormatterSinkProvider();
ssr.TypeFilterLevel = TypeFilterLevel.Full;

IWebProxy proxy = new WebProxy("proxy.sharda.mahindrabt.com", 80);
ICredentials ic = new NetworkCredential("myself", "123");
proxy.Credentials = ic;

IDictionary id = new Hashtable();
id["port"] = 9113;
id["typeFilterLevel"] = TypeFilterLevel.Full;
id["name"] = System.Guid.NewGuid().ToString();

id["proxyName"] = "proxy.sharda.mahindrabt.com";
id["proxyPort"] = 80;
id["machineName"] = "DSCP01214Jayant";
id["credentials"] = ic;
id["unsafeAuthenticatedConnectionSharing"] = true;
HttpChannel htc = new HttpChannel(id, scl, ssr);
ChannelServices.RegisterChannel(htc);

RemotingConfiguration.RegisterWellKnownServiceType(typeof (Mediator), "Chat.soap", WellKnownObjectMode.Singleton);
Console.WriteLine("Server running at Http port: 9113 and Tcp port: 5678");



Client code:
uname = "myself";
pwd = "123";
SoapClientFormatterSinkProvider scl = new SoapClientFormatterSinkProvider();
SoapServerFormatterSinkProvider ssr = new SoapServerFormatterSinkProvider();
ssr.TypeFilterLevel = TypeFilterLevel.Full;

IWebProxy proxy = new WebProxy("proxy.sharda.mahindrabt.com", 80);

if (txtProxyUserName.Text == string.Empty ||
txtProxyPassword.Text == string.Empty)
{
ic = new NetworkCredential(uname, pwd);
}
else
{
ic = new NetworkCredential(txtProxyUserName.Text,
txtProxyPassword.Text);
}
proxy.Credentials = ic;

id = new Hashtable();
id["port"] = 0;
id["typeFilterLevel"] = TypeFilterLevel.Full;
id["name"] = System.Guid.NewGuid().ToString();
id["preauthenticate"] = true;
id["proxyName"] = "proxy.sharda.mahindrabt.com";
id["proxyPort"] = 80;
id["machineName"] = "DSCP01214Jayant";
id["credentials"] = ic;
id["unsafeAuthenticatedConnectionSharing"] = true;

HttpChannel htc = new HttpChannel(id, scl, ssr);
ChannelServices.RegisterChannel(htc);
this.SetChannelProxy(htc, proxy);

im = (IMediator) Activator.GetObject(typeof (IMediator), "http://localhost:9113/Chat.soap");

result = true;
}
catch (Exception ex)
{
result = false;
stsConnected.Text = string.Empty;
stsConnected.Text = "An error occured. Message: " + ex.Message;
lblErrorMessage.Text = "An error occurred: " + ex.Message;
}
finally
{
}
return result;
}

private void SetChannelProxy( HttpChannel channel, IWebProxy proxy )
{
//get the channel data
FieldInfo clientChannelFieldInfo = typeof(HttpChannel).GetField("_clientChannel", BindingFlags.Instance | BindingFlags.NonPublic);


//cast it to httpclientchannel to get an access to IWebProxy Class.
HttpClientChannel clientChannel = (HttpClientChannel) clientChannelFieldInfo.GetValue(channel);


//get Proxy object
FieldInfo proxyObjectFieldInfo = typeof(HttpClientChannel).GetField("_proxyObject", BindingFlags.Instance | BindingFlags.NonPublic);


//set up proxy explicitly.
proxyObjectFieldInfo.SetValue(clientChannel, proxy );
}


Jayant D. Kulkarni
Brainbench Certified Software Engineer in C#, ASP.NET, .NET Framework and ADO.NET

Anders
June 20th, 2005, 05:07 AM
Yeah, I spent half last week figuring that out. My solution consist of three assemblies, server, client and common.

On server machine I have server.exe and common.dll.

On client machine I have client.exe and common.dll.

The common.dll contain declaration of delegates, an interface for the server, and a base class for the client.


public class Delegates {
public delegate void OnEventDelegate(object ob);
}

public interface IRemoteServer
{
event Delegates.OnEventDelegate OnEvent;
}

public class Client : MarshalByRefObject
{

IRemoteServer server;
public IRemoteServer Server
{
get
{
return server;
}

set
{
server = value;
}
}

public Client()
{
}

public void CreateRemoteObject(string RemoteURL, int LocalPort)
{
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();

IDictionary props = new Hashtable();
props["port"] = LocalPort;

TcpChannel chan = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(chan);

// ChannelServices.RegisterChannel(new TcpChannel());
Server = (IRemoteServer)Activator.GetObject(typeof(IRemoteServer), RemoteURL);
}


protected Delegates.OnEventDelegate D;
public void SubscribeEvent()
{
D = new Delegates.OnEventDelegate(onEvent);
Server.OnEvent += D;
}

public void UnSubscribeEvent()
{
Server.OnEvent -= D;
D = null;
}

public void onEvent(object ob)
{
this.OnEvent(ob);
}

public virtual void OnEvent(object ob)
{
}
}


The server implements the IRemoteServer interface, and in my testcase raises the event every few seconds:


public class RemoteServer : MarshalByRefObject, IRemoteServer
{
event Delegates.OnEventDelegate onEvent;
public event Delegates.OnEventDelegate OnEvent
{
add
{
onEvent += value;
}
remove
{
onEvent -= value;
}
}

protected void InvokeOnEvent(object ob) {
if (onEvent != null)
{
onEvent(ob);
}
}

System.Timers.Timer T = new System.Timers.Timer();

public void Start()
{
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();

IDictionary props = new Hashtable();
props["port"] = 50050;

TcpChannel chan = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(chan);

// ChannelServices.RegisterChannel(new TcpChannel(50050));
RemotingServices.Marshal(this, "RemoteServer");
T.Interval = 5000;
T.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsed);
T.Enabled = true;
}

void OnElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
InvokeOnEvent(e.SignalTime.ToString());
}
}



Then my "real" client inherits this class and implements the OnEvent method:


public class CClient : Client
{
public CClient()
{
this.CreateRemoteObject("tcp://192.168.1.107:50050/RemoteServer", 1234);
SubscribeEvent();
}

public override void OnEvent(object ob)
{
System.Diagnostics.Trace.WriteLine(ob);
}

}


So, as it appears to me, the key is to have all event code (delegates and handlers) on both the server and the client. Hence the common.dll.

I'm not fully satisfied though, with the base clients onEvent being public, and so on, but at least this works.

HTH!