Effective C #: 4. Using the Class Factory mode
Interface-based client activation remote object (below)
Chen Ming Microsoft C # /. Net Asia MVP
Difficulty: 7/10
Easy distributed applications are undoubtedly the most compelling part of the .NET platform. By using .NET Remoting technology, we can easily cross the boundary of the runtime, threads, or processes, even through the Internet to access an object on another computer far in his country. Moreover, this remote access is almost transparent - after some initialization work of the remote object, the call to the method is almost identical to the normal local object.
Depending on the lifecycle control method, .NET Remoting divides remote objects into server activation objects (SAO, Server ActiVated Object) and customer activation objects (Cao, Client Activated Object). As the name suggests, the server masters the power of Sao objects, and more specifically, the number of remote objects generated by the server control and which remote objects are processed by each customer; Independent remote objects, each method call will be assigned to remote objects associated with this customer. The living cycle of the CAO object is controlled by the client by regularly updating it to the "lease protocol" signed by the server.
Let's take a look at the situation of Sao. The following is a simple .NET Remoting Sao object application full programs:
//share.cs, Remote Object
Namespace Effective.csharp.chapter4 {
// Must Inherit from MarshalByrefObject
Public Class RemoteObject: System.MarshalByrefObject {
// a Very Simple Method IMPLEmentation
Public String Sayhello (String Name) {
Return "Hello," Name;
}
}
}
//server.cs, Server Side Code
Using system.runtime.remoting;
Using system.runtime.remoting.channels;
Using system.runtime.remoting.channels.tcp;
Namespace Effective.csharp.chapter4 {
Public class server {
Public static int main () {
// register the channel
Tcpchannel CHAN = New TcpChannel (8085);
ChannelServices.RegisterChannel (CHAN);
// register the remote object
RemotingConfiguration.registerWellkNownServiceType
TYPE.GETTYPE ("Effective.csharp.chapter4.RemoteObject, Share",
"Hello.rem", wellknownobjectmode.singlecall;
// Hold The Server, Wait for Client
System.console.writeline ("Hit
System.console.readline ();
Return 0;
}
}
}
//client.cs, client side code concernsing system;
Using system.runtime.remoting;
Using system.runtime.remoting.channels;
Using system.runtime.remoting.channels.tcp;
Namespace Effective.csharp.chapter4 {
Public Class Client
{
Public static int main ()
{
TCPCHANNEL CHAN = New TCPChannel ();
ChannelServices.RegisterChannel (CHAN);
// Create the Remote Object
RemoteObject Obj =
(RemoteObject) Activator.getObject (
TypeOf (RemoteObject), "TCP: // localhost: 8085 / hello.rem");
Console.writeline (Obj.Sayhello ("world");
Return 0;
}
}
}
The entire application is actually broken down into three independent compilation: Share.cs contains the definition of remote object RemoteObject, server.cs is the server-side code for creating and maintaining RemoteObject, and client.cs is the customer who actually applies RemoteObject. A particularly needed question is: Client.cs code multiple times a RemoteObject type (just contrary, server.cs did not directly reference RemoteObject). In Terms 1 We have mentioned that if you use the type defined in a class, you must use the / r option reference to the associated class set during compilation. In other words, the Share class set must be explicitly referred to when compiling client.cs, and the Client application after compiling is not possible to run correctly without the SHARE class set:
CSC Server.cs
CSC / T: Library Share.cs
CSC /R: Share.dll Client.cs
However, in real distributed applications, it is impossible to publish the remote object's implementation code and client programs - especially when these objects are used to implement some critical algorithms (such as encryption, user verification, etc.) time!
In fact, the client's compilation and operation do not really need the implementation of the remote object - the client is only responsible for converting the call to the call into a message, and then send it to the server for further processing. The reason why you need to reference a class set containing a remote object implementation, just because the compiler needs to verify the parameters of these methods to call the code and the return value type correctly correct, and the runtime needs to use this information to convert the method to a message. That is, the compilation of the client program really needs only the type metadata (Metadata) of the remote object, not an implementation!
An obvious solution thus thinking is to use interfaces and abstract bases - they exactly use to separate specific class implementations with class methods. The program code for implementing the above remote object application instance is given below:
//share.cs, Remote Object Interface Definition
Namespace Effective.csharp.chapter4 {
Public interface IREMOTEOBJECT {
String Sayhello (String Name);
}
}
//server.cs, Server Side Code
Using system.runtime.remoting;
Using system.runtime.remoting.channels;
Using system.runtime.remoting.channels.tcp;
Namespace Effective.csharp.chapter4 {// Must Inherit from MarshalByrefObject
Public Class RemoteObject: System.MarshalByrefObject, IremoteObject {
// a Very Simple Method IMPLEmentation
Public String Sayhello (String Name) {
Return "Hello," Name;
}
}
Public class server {
Public static int main () {
// register the channel
Tcpchannel CHAN = New TcpChannel (8085);
ChannelServices.RegisterChannel (CHAN);
// register the remote object
RemotingConfiguration.registerWellkNownServiceType
Type.gettype ("Effective.csharp.chapter4.RemoteObject, Server",
"Hello.rem", wellknownobjectmode.singlecall;
// Hold The Server, Wait for Client
System.console.writeline ("Hit
System.console.readline ();
Return 0;
}
}
}
//client.cs, Client Side Code
Using system;
Using system.runtime.remoting;
Using system.runtime.remoting.channels;
Using system.runtime.remoting.channels.tcp;
Namespace Effective.csharp.chapter4 {
Public Class Client
{
Public static int main ()
{
TCPCHANNEL CHAN = New TCPChannel ();
ChannelServices.RegisterChannel (CHAN);
// Create the Remote Object
IremoteObject Obj =
(IRemoteObject) activator.getObject (
TypeOf (IremoteObject), "TCP: // localhost: 8085 / hello.rem");
Console.writeline (Obj.Sayhello ("world");
Return 0;
}
}
}
The entire application is still divided into three parts, but this time Share.cs no longer contains the implementation of the remote object, but is merely an interface for describing the remote object method. The actual implementation of the remote object is transferred to Server.cs. This way, only the interface defined in Share.cs is required during the compilation process of Client.cs and Server.cs:
CSC / T: Library Share.cs
CSC /R: Share.dll Client.cs
CSC /R:Share.dll Server.cs
The actual released client program only needs to include Client.exe and Share.dll, no longer include the code implemented by the remote object method.
In addition to using the interface, the SOAPSUDS.EXE tools provided using the .NET framework can also complete the above work. SOAPSUDS can separate the type defined metadata information from an existing class, and the separated portion can be used for the compilation and release of client code: // Extract Remote Object metadata from Share.dll
SOAPSUDS -TYPES: Effective.csharp.chapter4.RemoteObject, Share
-OA: RemoteObject.dll
// Compile the client useing extraducted DLL
CSC /R: RemoteObject.dll Client.cs
Compared with the solution to use the interface, use the soapsuds tool to be simple, but use interface inheritable to make your remote objects with polymorphic feature - the same client does not need any changes to any one to implement specific The remote object of the interface. Moreover, the solution to the interface should be clearer. - How many confused programs will be confused. (Endlessly)
* This article is originally original, please do not reprint without the author's license.