We are having an odd problem with .NET Remoting. Basically, we have a server which registers two TcpChannels with ChannelServices.RegisterChannel()
:
We then have a client that registers a TcpChannel to be able to communicate with the server. We retrieve a an object from the server by calling Activator.GetObject()
with the URI
"tcp://serverip:50000/objectname"
and this works fine, the client connects to the server on port 50000 and gets the object.
However, when we start calling methods on that object, the connection to the channel on port 50000 is dropped, and a new connection is made to the channel on port 15000 automatically. This poses a real problem for us since we don't want traffic on port 15000 because that channel may not be bound to the same network adapter as the port 50000 channel on the server or that port may not be open in the firewall, which causes the remoting calls to fail naturally.
This is very strange to us since the client has no knowledge in our code that there exists another channel on the server on port 15000 or what IP it listens on, yet it attempt to connect to it.
Any help on this is greatly appreciated,
Thanks, Casper
This is the code that sets up one of the server channels, the one usually on port 50000:
IDictionary props = new Hashtable();
props["port"] = m_tcpPort;
props["name"] = String.Empty;
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
m_tcpChannel = new TcpServerChannel( props, /*clientProvider,*/ serverProvider );
ChannelServices.RegisterChannel( m_tcpChannel, false );
m_wellKnownObjRef = RemotingServices.Marshal( this, "Server@" + m_tcpPort.ToString() );
This is the code that sets up the other server channel, usually on port 15000:
IDictionary props = new Hashtable();
props["name"] = String.Empty;
props["port"] = ip.Port;
props["bindTo"] = ip.Address.ToString();
props["timeout"] = REMOTING_TIMEOUT; // Timeout to prevent hung remoting calls.
if (!String.IsNullOrEmpty( machineName ))
{
props["machineName"] = machineName;
}
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
m_channel = new TcpChannel( props, clientProvider, serverProvider );
ChannelServices.RegisterChannel( m_channel, false );
m_objRef = RemotingServices.Marshal( this, QueueName ); // Queuename is a GUID.
This is the code in the client that connects to the first server channel, the one that's usually on port 50000:
IDictionary props = new Hashtable();
props["port"] = 0;
RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
m_tcpChannel = new TcpClientChannel(props, clientProvider/*, serverProvider*/);
ChannelServices.RegisterChannel(m_tcpChannel, false );
string address = "tcp://" + profile.RemoteIP + ":" + profile.RemoteTCP;
m_server = (Kernel)Activator.GetObject(typeof(Server), address + "/Server@" + port);
We've logged a support case with Microsoft about this and apparently, what we're doing here is not supported by .NET Remoting. You are only allowed to register one channel of each type in one AppDomain. What Remoting does is that it sends back the URI of the object to the client to tell it where it can access the object in question. When it does that it looks through the registered channels at the server end and uses the first channel that it finds there that matches the type requested (in our case: Tcp). In other words it will use whatever channel happens to get registered first. It doesn't care at all about what channel the client has connected on.
The solution is to implement your own IClientChannelSinkProvider on the client side. When you implement the CreateSink() method you can choose what url you want the client to connect to when you create the sink to use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With