http://www.glaacialcomponents.com/articledetail.aspx?articleid=caomn
(Translation ...)
Introduction "When I create a CAO from inside my network / router, everything works fine.? However, when I have a client outside my network that creates a CAO inside the network, it fails the first time I call a function.? What am I doing wrong!?!?! "
"In the internal network, I generate a client activation object (CAO), all of which are normal. When my client is in the external network, when I call the remote object, I got a failure result, I am wrong where?"
I Hear this Questions ON NewsGroups and Bulletin Boards Almost Every Day. The answer iswer IS Actually Pretty StraightForward AlthiSh CAN Get Deeper if you wish to spice up the functionality.
I often hear such a problem almost every day. If you just want to solve the problem, the answer is very simple; of course, you can try the mechanism after exploring, you will find that interesting.
Why this happens
When a CAO is created the server returns a URI that points to the unique instance of the CAO on the server.?This is how the server knows the unique instance you are using. (This is also why its very difficult to load balance CAO objects ) .THE URI That The Server Sends Back Contains Either The IP You Tell It That It Really IS.
When the server generates CAO, it also generates a URI, the server indicates an object instance used by the remote client according to this URI. The URI contains information on the actual IP of the server. (If the server is in the internal network, this IP is an internal IP, which is the root of the problem)
How To FIX IT (The Quick FIX)
The simple fix for this that will work on most setups is to set the 'machineName' property of the channel on the server to the EXTERNAL ip that the client sees. This allows the server to return the external ip instead of its local internal IP. Typically you want to set the machineName equal to the EXTERNAL ip. This is the IP that your firewall or router has. This is also the IP that machines will see from outside your LAN when they go to connect to your remote object. Quick Fix
The simplest correction method is to set the 'MachineName' attribute of the channel as an external IP address; so that the server returns to the client will be an external IP address;
You can complete the settings with the code. (Note: You can modify the configuration file)
For example, for a tcpchannel you would do the following on the server side of your code.
IDictionary prop = new hashtable ();
Prop ["Port"] = 4000;
Prop ["MachineName"] = "myexternalip.com";
Tcpchannel = New TcpChannel (Prop, Null, NULL);
ChannelServices.RegisterChannel (TCPChannel);
That's all you need.?your server sales y p / firewall / router.
There Is A Second Method of Fixing This Problem Which is Much More Complete, Yet More Complicated
A Complete Solution
What Do I do if I need to access the server from Both Inside the lan all.com to know something mildly technical like that The machineName fix is ok, but it leaves a lot to be desired in many situations. This can be a real problem if its for a home or small business application where you may or may not have someone with a CLUE. Wouldn't it Be Easier if We Just Had A Solution That Worked Everywhere Well your in luck! Because thats exactly what this is. This solution uses the IP that the CLIENT sees the server as (which you of course know or the client would not be able to even connect to the server in the first place. If I do not want to set "machine Name "Properties, what should I do? There are many reasons to make me have such a requirement, for example, I may not know the router's IP. Since the client knows the server IP, we can use this IP, replace the previous property settings Plan?
This solution also works very well where you have a multi-homed server (common in corporate intranets). A server with multiple NIC cards may be seen by many IPs each requiring a different route in and out of the server.This will work perfectly for That Situation as Well.
So How do I create a cao on a Server and have it work regardless if I'm inside or outside the local network. The answer lies in a rarely used class called the TrackingHandler. The basic process is as follows. We create our SAO Class Factory first, then when we go to create our CAO, we send the IP the client sees the server as in the creation call . This then puts the information in the CallContext where the tracking handler picks it up when it is fired during CAO creation and return.The tracking handler takes the URI that is being returned and replaces the server address with the address you have told the server you See it it is on, Your Cao Will Work Flawnessly Against the Server, You Never Have To Do Another Thing. Solution is to use TrackingHandler, this is a rare class. The basic process is such that before generating a CAO object, we pass the IP information into the CallContext (calling the environment) and then get the IP information through the Tracking Handler, and use it to process the URI.
Now That I've Given You The Overview, Lets Get Into The Details.
First, this approach assumes that you are using a simple factory pattern to create your CAO.? You can see an explanation of factory pattern CAO creation in my article here.? This will also work if you use interfaces instead of abstract classes but for the Purposes of this Article We Will Focus on Abstract Class Share Type.
The factory create method for your CAO should accept a string.? This string will hold the address the client sees the server as.? Define it first in the abstract class then implement it in your SAO factory implementation.? I included a regular factory implementation Along with the address based one so you can seeboth approaches.
// Share.dll Abstract Sao Factory
Namespace Sharedll
{
Public Abstract Class SaocaClassFactoryDef: MarshalByrefObject
{
Public Abstract Caoclassdef CreatecaClass ();
Public Abstract CaoclassDef CreatecaClass (String Strip);
}
}
// Implementation SaoCaoclassFactory.cs
Public Class SaoCaoclassFactory: Sharedll.saocaoclassFactoryDef
{
Public Override Caoclassdef CreatecaClass ()
{
// this Is Important to Clear Out or it will get the address you left in A Previous Factory C
CallContext.FreenamedDataSlot ("Observedip");
Return new caoclass ();
// Class Factory Create
}
Public Override Caoclassdef CreatecaClass (String straddress)
{
CallContext.SetData ("Observedip", straddress;
Return new caoclass ();
// Class Factory Create
}
}
Now That We Have The Address In The Call Context We can IMPLEMENT OUR TRACKING HANDLER.?
Our Tracking Handler Will Grab The Address Out of The Call Context and Insert It Into the URI.
// TrackingHandler.cs in server.exe
Public Class ExampleTrackingHandler: ItrackingHandler
{
// Notify a Handler That An Object Has Been Marshaled.
Public void MarshaledObject (Object Obj, Objref OR)
{// Assumption: We Have a Server Channel Sink That Sets a Call Context Flag
// Called "Observedip" WHENEVER WE Are Processing a Remote Request Object
Observedip = CallContext.getdata ("Observedip");
// for local clients we don't do anything here
// if They don't specify the remote ip Then We Just Use the Servers IP
IF (Observedip == Null)
Return;
IF (Or.ChannelInfo == Null)
Return;
String straddress = (string) Observedip;
For (int i = or.channelinfo.channelData.getLowerBound (0);
i <= or.channelinfo.channeldata.getupperbound (0); i )
{
// check for the channelatastore Object this we don't want to copy
IF (or.channelinfo.channelData [i] is channelataStore) {
// Personally I don't know why channeluris is an array ... i am only
// Familiar with there being one Uri in Each ChannelDataStore Object
Foreach (String Uri In ((CHANNELDATASTORE) Or.ChannelInfo.channelData [i]). Channeluris)
{// this Will Get The First Part of The URI
INT Noffset = Uri.indexof ("//") 2;
String strnewuri = uri.substring (0, noffset);
Strnewuri = straddress; noffset = uri.indexof (":", noffset;
Strnewuri = uri.substring (Noffset, Uri.Length - Noffset);
String [] stratay = new string [1] {strnewuri};
ChannelDataStore CDS = New ChannelDataStore (Strarray);
Or.ChannelInfo.channelData [i] = cds;}}}}}
We have our class factory and our tracking handler, the last thing we need to do is make sure we register our tracking handler during the registration in our server. We do that with the simple RegisterTrackingHandler.
ChannelServices.RegisterChannel (New Tcpchannel (4000));
// this Will Handle Converting The Returned Cao Uri To The Correct Server IP
TRACKINGSERVICES.REGISTERTRACKINGHANDLER (New ExampleTrackingHandler ());
TYPE THISTYPE = Type.gettype ("Server.saocaoclassFactory, Server");
RemotingConfiguration.registerwellknownServiceType (Thistype,
"Saocaoclassfactoryuri", wellknownobjectmode.singlecall;
Thats all you need !? At this point you can instantiate your CAO from the client with your SAO factory.?If you have any comments, recommendations, questions, feel free to contact me. I try to answer? All of my email.