Manually instantiating and associating Calculator with an endpoint
public static void Main( )
{
// create a channel and register it
HttpChannel chan = new HttpChannel(65100);
ChannelServices.RegisterChannel(chan);
// make your own instance and call Marshal directly
Calculator calculator = new Calculator( );
RemotingServices.Marshal(calculator,"theEndPoint");
// "They also serve who only stand and wait."); (Milton)
Console.WriteLine("Press [enter] to exit...");
Console.ReadLine( );
}
The net effect is that you have instantiated a calculator object, and associated a proxy for remoting with the endpoint you've specified.
19.3.7 Understanding Endpoints
What is going on when you register this endpoint? Clearly, the server is associating that endpoint with the object you've created, and when the client connects that endpoint is used as an index into a table so that the server can provide a proxy to the correct object (in this case, the Calculator).
If you don't provide an endpoint for the client to talk to, you can instead write all the information about your calculator object to a file and physically give that file to your client. For example, you could send it to your buddy by email, and he could load it on his local computer.
page 417
Programming C#
The client can deserialize the object and reconstitute a proxy which it can then use to access the calculator on your server! (The following example was suggested to me by Mike Woodring of DevelopMentor, who uses a similar example to drive home the idea that the endpoint is simply a convenience for accessing a marshaled object remotely.)
To see how you can invoke an object without a known endpoint, modify the Main( ) method of Example 19-3 once again. This time, rather than calling Marshal( ) with an endpoint, just pass in the object:
ObjRef objRef = RemotingServices.Marshal(calculator)
Marshal( ) returns an ObjRef object. An ObjRef object stores all the information required to activate and communicate with a remote object. When you do supply an endpoint, the server creates a table that associates the endpoint with an objRef so that the server can create the proxy when a client asks for it. ObjRef contains all the information needed by the client to build a proxy, and ObjRef itself is serializable.
Open a file stream for writing to a new file and create a new SOAP formatter. You can serialize your ObjRef to that file by invoking the Serialize( ) method on the formatter, passing in the file stream and the ObjRef you got back from Marshal. Presto! You have all the information you need to create a proxy to your object written out to a disk file. The complete replacement for Main( ) is shown in Example 19-6.
Example 19-6. Marshaling an object without a well-known endpoint
public static void Main( )
{
// create a channel and register it
HttpChannel chan = new HttpChannel(65100);
ChannelServices.RegisterChannel(chan);
// make your own instance and call Marshal directly
Calculator calculator = new Calculator( );
ObjRef objRef = RemotingServices.Marshal(calculator);
FileStream fileStream =
new FileStream("calculatorSoap.txt",FileMode.Create);
SoapFormatter soapFormatter = new SoapFormatter( );
soapFormatter.Serialize(fileStream,objRef);
fileStream.Close( );
// "They also serve who only stand and wait."); (Milton)
Console.WriteLine(
"Exported to CalculatorSoap.txt. Press ENTER to exit...");
Console.ReadLine( );
}
When you run the server, it writes the file calculatorSoap.txt to the disk. The server then waits for the client to connect. It might have a long wait.
You can take that file to your client and reconstitute it on the client machine. To do so, again create a channel and register it. This time, however, open a fileStream on the file you just copied from the server:
FileStream fileStream =
page 418
Programming C#
new FileStream ("calculatorSoap.txt", FileMode.Open);
Then instantiate a SoapFormatter and call Deserialize( ) on the formatter, passing in the filename and getting back an ObjRef:
SoapFormatter soapFormatter =
new SoapFormatter ( );
try
{
ObjRef objRef =
(ObjRef) soapFormatter.Deserialize (fileStream);
You are ready to unmarshall that ObjRef, getting back an ICalc reference:
ICalc calc =
(ICalc) RemotingServices.Unmarshal(objRef);
You are now free to invoke methods on the server through that ICalc, which will act as a proxy to the calculator object running on the server that you described in the calculatorSoap.txt file. The complete replacement for the client is shown in Example 19-7.
Example 19-7. Replacement of Main( ) from Example 19-4 (the client)
public static void Main( )
{
int[] myIntArray = new int[3];
Console.WriteLine("Watson, come here I need you...");
// create an Http channel and register it
// uses port 0 to indicate you won't be listening
HttpChannel chan = new HttpChannel(0);
ChannelServices.RegisterChannel(chan);
FileStream fileStream =
new FileStream ("calculatorSoap.txt", FileMode.Open);
SoapFormatter soapFormatter =
new SoapFormatter ( );
try
{
ObjRef objRef =
(ObjRef) soapFormatter.Deserialize (fileStream);
ICalc calc =
(ICalc) RemotingServices.Unmarshal(objRef);
// use the interface to call methods
double sum = calc.Add(3.0,4.0);
double difference = calc.Sub(3,4);
double product = calc.Mult(3,4);
double quotient = calc.Div(3,4);
// print the results
Console.WriteLine("3+4 = {0}", sum);
Console.WriteLine("3-4 = {0}", difference);
Console.WriteLine("3*4 = {0}", product);
Console.WriteLine("3/4 = {0}", quotient);
}
catch( System.Exception ex )
{
page 419
|