Remoting : Server calling another [modified]
-
Apologies for the vague thread title, the following is a tad complicated to summarise well. Anyway, enough excuses... Lets say I have a multi tier application that consists of 1 client and 2 server applications (A & B). Both servers have remoting listener services each of which are entirely self contained and do not share any common sinks, both remoting frameworks contain a custom encryption sink (each of which are entirely independent implementations) In my current setup, the client pushes all its requests to server A. Some of these are handled within A others require a server A to server B remoting call. Now here's the problem: When server A is invoked by the client and this requires a remoting call to server B the call from A to B fails with a CryptographicException. It seems that for some reason the A to B encryption sink is not being called, so when B receives the data it cannot decrypt as the format is invalid. Does anybody have any ideas of what could be happening here? p.s. Interesting if I code the client to remote directly to A or B then these calls work without any issues.
modified on Wednesday, September 10, 2008 1:05 PM
-
Apologies for the vague thread title, the following is a tad complicated to summarise well. Anyway, enough excuses... Lets say I have a multi tier application that consists of 1 client and 2 server applications (A & B). Both servers have remoting listener services each of which are entirely self contained and do not share any common sinks, both remoting frameworks contain a custom encryption sink (each of which are entirely independent implementations) In my current setup, the client pushes all its requests to server A. Some of these are handled within A others require a server A to server B remoting call. Now here's the problem: When server A is invoked by the client and this requires a remoting call to server B the call from A to B fails with a CryptographicException. It seems that for some reason the A to B encryption sink is not being called, so when B receives the data it cannot decrypt as the format is invalid. Does anybody have any ideas of what could be happening here? p.s. Interesting if I code the client to remote directly to A or B then these calls work without any issues.
modified on Wednesday, September 10, 2008 1:05 PM
I think its a 'Serialization' issue. I am not sure but, Try without encryption. If it still gives you error then its a problem of Serialization else your encription methods mismatched.
-
Apologies for the vague thread title, the following is a tad complicated to summarise well. Anyway, enough excuses... Lets say I have a multi tier application that consists of 1 client and 2 server applications (A & B). Both servers have remoting listener services each of which are entirely self contained and do not share any common sinks, both remoting frameworks contain a custom encryption sink (each of which are entirely independent implementations) In my current setup, the client pushes all its requests to server A. Some of these are handled within A others require a server A to server B remoting call. Now here's the problem: When server A is invoked by the client and this requires a remoting call to server B the call from A to B fails with a CryptographicException. It seems that for some reason the A to B encryption sink is not being called, so when B receives the data it cannot decrypt as the format is invalid. Does anybody have any ideas of what could be happening here? p.s. Interesting if I code the client to remote directly to A or B then these calls work without any issues.
modified on Wednesday, September 10, 2008 1:05 PM
I've found this issue with double hop applications before. Something, and I could never figure out what, caused the code to fall over with an invalid key issue.
Deja View - the feeling that you've seen this post before.
-
I've found this issue with double hop applications before. Something, and I could never figure out what, caused the code to fall over with an invalid key issue.
Deja View - the feeling that you've seen this post before.
After much hair pulling I have found a solution to this problem, I am not particularly happy with it but it is a solution none the less. After doing some further debugging it seems that when the A to B request is made the .NET Framework pushes this into the incorrect channel (i.e. the Client to A) as this channel has different sinks, when B receives the data it is unable to process it. Interestingly if I unregistered the Client to A channel the A to B call would work, obviously this isn't a solution as this then breaks all Client to A comms. At first it seemed that the solution was obvious, make sure that the correct channel is used. After much googling I have been unable to find a method of doing this. I did however find alot of people with the same problem ;) So the solution... The server B remoting framework has a client library which is installed on A. This library contains all the methods that B exposes across remoting. The solution was to create a wrapper around this client library, on instantiation the wrapper creates a new AppDomain and loads the client library into it. I then use a marhsalled transparent proxy object across to call the client library. Doing this means that the new AppDomain on has a single TcpChannel registered and therefore the selection issue doesn't exist. As always with these things there was a gotcha, which is if you leave the AppDomain unused for more than 5 minutes (default) the lease expires and the proxy fails. This can be fixed by, in the client library, overriding "InitializeLifetimeService" and returning null. So, wrapper code:
public sealed class ClientLibraryWrapper
{
AppDomain clientDomain;
ServerB.Client.EntryPoint client;public ClientLibraryWrapper { this.clientDomain = AppDomain.CreateDomain("ServerBClientDomain"); Assembly clientAssembly = Assembly.LoadFile(Environment.CurrentDirectory + @"\\ServerB.Client.dll"); this.clientDomain.Load(clientAssembly.FullName); Object obj = mhsClientDomain.CreateInstanceAndUnwrap(clientAssembly.FullName, "ServerB.Client.EntryPoint"); this.client = (ServerB.Client.EntryPoint)obj; } public int ServerBMethod() { this.client.ServerBMethod(); }
}
Client library code:
public sealed class EntryPoint : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null;
}public int ServerBMethod() { return 1; }
}