Microsoft. NET remoting
I. remoting Basics
What is remoting? In short, we can regard it as a distributed processing method. From the perspective of Microsoft products, it can be said that remoting is an upgrade of DCOM, which improves many functions and is well integrated into the. NET platform. Microsoft. NET remoting provides a framework that allows an object to interact with another object through an application domain. This is exactly why remoting is used. Why? In Windows, applications are separated into separate processes. This process forms a boundary around the application code and data. If the inter-process communication (RPC) mechanism is not used, the Code executed in one process cannot access another process. This is an operating system's protection mechanism for applications. However, in some cases, We need to cross the application domain and communicate with another application domain, that is, cross the border.
In remoting, a channel is used to implement object communication between two application domains. :
First, the client uses remoting to access the channel to obtain the server object, and then parses it as the client object through proxy. This provides a possibility to publish server objects as a service. Remote Object code can run on a server (such as an object activated by the server and an object activated by the client). Then, the client connects to the server through remoting to obtain the service object and serialize it to the client.
In remoting, in addition to the channel type and port number, the designer does not need to know the data packet format for the objects to be transmitted. However, it must be noted that when obtaining the server-side object, the client does not obtain the actual server-side object, but obtains its reference. This ensures loose coupling between client and server objects, and optimizes communication performance.
1. Two remoting Channels
There are two main remoting channels: TCP and HTTP. In. net, the ichannel interface is defined in system. runtime. remoting. Channel. The ichannel interface includes the tcpchannel and HTTP channel types. They correspond to the two types of remoting channels respectively.
The tcpchannel type is stored in the namespace system. runtime. remoting. Channel. TCP. The TCP channel provides a socket-based transmission tool that uses the TCP protocol to transmit serialized message streams across the remoting boundary. The tcpchannel type serializes message objects in binary format by default, so it has higher transmission performance. The httpchannel type is stored in the namespace system. runtime. remoting. Channel. HTTP. It provides an HTTP protocol for transmitting serialized message streams over the Internet through the firewall. By default, the httpchannel type serializes message objects in soap format, so it has better interoperability. Generally, we use tcpchannel more in the LAN; if we want to cross the firewall, we use httpchannel.
2. Remote Object Activation Method
Before accessing an object instance of the remote type, you must create it and initialize it through a process named activation. This client creates a remote object through a channel, which is called object activation. In remoting, remote object activation can be divided into two categories: server-side activation and client activation.
(1) server activation is also called the wellknow method, and many of them are translated as well-known objects. Why is it called the activation mode of well-known objects? The reason is that the server application will publish this type in a well-known Uniform Resource Identifier (URI) before activating the object instance. The server process then configures a wellknown object for this type and publishes the object based on the specified port or address .. Net remoting divides server activation into Singleton mode and singlecall mode.
Singleton mode: stateful mode. If it is set to singleton activation mode, remoting creates the same object instance for all clients. When an object is active, the singleton instance processes all subsequent client access requests, regardless of whether they are the same client or other clients. The Singleton instance will remain in the status of the method call. For example, if a remote object has an accumulation method (I = 0; ++ I), it is called by multiple clients (for example, two. If it is set to singleton mode, the first customer gets the value 1, and the second customer gets the value 2 because they get the same object instance. If you are familiar with ASP. NET status management, we can regard it as an application status.
Singlecall mode: singlecall is a stateless mode. Once set to singlecall mode, remoting creates a remote object instance for each client when the client calls the remote object method. GC automatically manages the destruction of the object instance. In the same example, the two clients accessing the remote object obtain 1. We can still consider ASP. NET as a session state.
(2) activate the client. Unlike the wellknown mode, remoting assigns a URI for each client activation type when activating each object instance. Once a client request is obtained in the client activation mode, an instance reference is created for each client. The singlecall mode differs from the client activation mode: first, the creation time of the object instance is different. The client activation method is instantiated once the customer sends a call request, while the singlecall method is created when the object method is called. Second, the objects activated in singlecall mode are stateless, and the object lifecycle is managed by GC, while the objects activated on the client are stateful, and their lifecycles can be customized. Third, the two activation modes have different implementation methods on the server side and the client side. Especially on the client, the singlecall mode is activated by GetObject (), which calls the default constructor of the object. The client activation mode is activated through createinstance (), which can pass parameters, so you can call a custom constructor to create an instance.
Ii. Definitions of remote objects
As mentioned above, when obtaining the server object, the client does not obtain the actual server object, but obtains its reference. Therefore, in remoting, some definitions of remote objects must be followed.
Since the objects passed by remoting are referenced, the passed remote object class must inherit marshalbyrefobject. Msdn's description of externalbyrefobject is that externalbyrefobject is the base class of objects that communicate across application domain boundaries through proxy message exchange. Objects not inherited from externalbyrefobject are implicitly sent by value. When a Remote Application references a value-based object, a copy of the object is transferred across the remote processing boundary. Because you want to use the proxy method instead of the copy method for communication, you need to inherit marshallbyrefobject.
The following is the definition of a remote object class:
Public class serverobject: marshalbyrefobject
{
Public Person getpersoninfo (string name, string sex, int age)
{
Person = new person ();
Person. Name = Name;
Person. Sex = sex;
Person. Age = age;
Return person;
}
}
This class only implements the simplest method, namely setting the basic information of a person and returning a person class object. Note the person class returned here. Since the person passed here is completed by passing the value, and remoting must be a referenced object, the person class must be serialized.
Therefore, in a remote object in remoting, if you want to call or pass an object, such as a class or structure, the class or structure must be serialized attribute [serializableattribute]:
[Serializable]
Public class person
{
Public Person ()
{
}
Private string name;
Private string sex;
Private int age;
Public string name
{
Get {return name ;}
Set {name = value ;}
}
Public String sex
{
Get {return sex ;}
Set {sex = value ;}
}
Public int age
{
Get {return age ;}
Set {age = value ;}
}
}
Compile the remote object into a DLL as a class library. This dll will be placed on the server and client respectively to add references.
Remote objects that can be passed in remoting can be of various types, including complex dataset objects, as long as they can be serialized. Remote objects can also contain events, but server-side processing of events is special. I will introduce it in the third part of this series.
Iii. Server
According to the first section, the implementation of different server ports of channel types varies according to the activation mode. In general, the server side should be divided into three steps:
1. Registration Channel
To communicate across application domains, you must implement a channel. As mentioned above, remoting provides the ichannel interface, which contains two types of channels: tcpchannel and httpchannel. In addition to the performance and the format of serialized data, these two types are implemented in the same way. Therefore, we will take tcpchannel as an example.
To register a tcpchannel, first add the reference "system. runtime. remoting" in the project, and then using namespace: system. runtime. remoting. Channel. TCP. The Code is as follows:
Tcpchannel channel = new tcpchannels (8080 );
Channelservices. registerchannel (Channel );
When instantiating a channel object, pass the port number as a parameter. Then call the static method registerchannel () to register the channel object.
2. Register a remote object
After the channel is registered, to activate a remote object, you must register the object in the channel. The method for registering objects varies depending on the activation mode.
(1) Singleton Mode
For wellknown objects, you can achieve remotingconfiguration. registerwellknownservicetype () through the static method: remotingconfiguration. registerwellknownservicetype (
Typeof (serverremoteobject. serverobject ),
"Servicemessage", wellknownobjectmode. Singleton );
(2) singlecall Mode
The method for registering an object is basically the same as the singleton mode. You only need to change the enumeration parameter wellknownobjectmode to singlecall. Remotingconfiguration. registerwellknownservicetype (
Typeof (serverremoteobject. serverobject ),
"Servicemessage", wellknownobjectmode. singlecall );
(3) Client activation mode
The method used for client activation is different, but the difference is not big. You can see the code at a glance.
Remotingconfiguration. applicationname = "servicemessage ";
Remotingconfiguration. registeractivatedservicetype (
Typeof (serverremoteobject. serverobject ));
Why do I need to set the applicationname Attribute before registering the object method? In fact, this property is the URI of the object. For the wellknown mode, Uri is placed in the parameters of the registerwellknownservicetype () method. Of course, you can assign values to the applicationname attribute. The registeractivatedservicetype () method does not have the applicationname parameter, so it must be separated.
3. logout Channel
If you want to disable the remoting service, you need to cancel the channel or disable the channel listening. In remoting, channel listening is automatically enabled when we register a channel. If listening to the channel is disabled, the channel cannot accept client requests, but the channel still exists. If you want to register the Channel again, an exception is thrown.
// Obtain the currently registered channel;
Ichannel [] channels = channelservices. registeredchannels;
// Close the channel named mytcp;
Foreach (ichannel eachchannel in channels)
{
If (eachchannel. channelname = "mytcp ")
{
Tcpchannel = (tcpchannel) eachchannel;
// Disable the listener;
Tcpchannel. stoplistening (null );
// Cancel the channel;
Channelservices. unregisterchannel (tcpchannel );
}
}
In the code, the registerdchannel attribute obtains the currently registered channel. In remoting, multiple channels can be registered at the same time, which will be described later.
Iv. Client
The client mainly performs two tasks: first, registering a channel. As shown in figure 1, both the server side and the client side of remoting must transmit messages through channels to obtain remote objects. The second step is to obtain the remote object.
1. Registration channel:
Tcpchannel channel = new tcpchannel ();
Channelservices. registerchannel (Channel );
Note that when the client instantiates a channel, it is the default constructor called, that is, no port number is passed. In fact, this port number is indispensable, but its designation is put behind as part of the URI.
2. Obtain the remote object.
Similar to the server, different activation modes determine the implementation of the client. However, the difference is only the difference between the wellknown activation mode and the client activation mode. For singleton and singlecall modes, the client implementation is identical.
(1) wellknown activation mode
To obtain a well-known remote object on the server, you can obtain it using the GetObject () method of the activator process:
Serverremoteobject. serverobject serverobj = (serverremoteobject. serverobject) activator. GetObject (
Typeof (serverremoteobject. serverobject), "TCP: // localhost: 8080/servicemessage ");
First, it is activated in wellknown mode. The client obtains the object by using GetObject (). The first parameter is the remote object type. The second parameter is the server Uri. For the HTTP channel, http: // localhost: 8080/servicemessage is used. Because I use a local machine, it is localhost. you can replace it with a specific server IP address. The port must be the same as the server port. The following is the remote object service name defined by the server, that is, the content of the applicationname attribute.
(2) Client activation mode
As mentioned above, the wellknown mode can only call the default constructor when creating an object on the client. The code above demonstrates this because the GetObject () method cannot pass the constructor parameters. The client activation mode allows you to create remote objects through custom constructor.
There are two methods to activate the client:
1) Call the static method registeractivatedclienttype () of remotingconfiguration (). The return value of this method is void, which only registers the remote object on the client. The object class constructor must be called for actual instantiation.
Remotingconfiguration. registeractivatedclienttype (
Typeof (serverremoteobject. serverobject ),
"TCP: // localhost: 8080/servicemessage ");
Serverremoteobject. serverobject serverobj = new serverremoteobject. serverobject ();
2) Call the createinstance () method of the activator process. This method creates class objects of the specified type of method parameters. Unlike the previous GetObject () method, GetObject () is used to call constructor on the client, while GetObject () only obtains the object, and instance creation is completed on the server. The createinstance () method has many reloads. I will focus on two of them.
A. Public static object createinstance (type, object [] ARGs, object [] activationattributes );
Parameter description:
Type: Type of the object to be created.
ARGs: array of parameters that match the number, sequence, and type of parameters to call the constructor. If ARGs is an empty array or a null reference (nothing in Visual Basic), the constructor without any parameters is called (default constructor ).
Activationattributes: contains one or more arrays of attributes that can be activated.
The args parameter here is an object [] array type. It can pass parameters in the constructor of the object to be created. Here, we can draw a conclusion: the remote object class passed by the wellknown activation mode can only use the default constructor, while the activated mode can be used for user-defined constructor. The activationattributes parameter is usually used to transmit the server URL in this method.
Assume that our remote object class serverobject has a constructor:
Serverobject (string pname, string comment X, int page)
{
Name = pname;
Sex = sex X;
Age = page;
}
The implementation code is:
Object [] attrs = {New urlattribute ("TCP: // localhost: 8080/servicemessage ")};
Object [] objs = new object [3];
Objs [0] = "wayfarer ";
Objs [1] = "male ";
Objs [2] = 28;
Serverremoteobject. serverobject = activator. createinstance (
Typeof (serverremoteobject. serverobject), objs, attrs );
As you can see, the objs [] array transmits the parameters of the constructor.
B. Public static objecthandle createinstance (string assemblyname, string typename, object [] activationattribute );
Parameter description:
Assemblyname: searches for the name of an assembly of the typename type. If assemblyname is a null reference (nothing in Visual Basic), search for the Assembly being executed.
Typename: name of the preferred type.
Activationattributes: contains one or more arrays of attributes that can be activated.
The parameter description is clear at a glance. Note that the returned value of this method is of the objecthandle type, so the code is different from the previous one:
Object [] attrs = {New urlattribute ("TCP: // localhost: 8080/echomessage ")};
Objecthandle handle = activator. createinstance ("serverremoteobject ",
"Serverremoteobject. serverobject", attrs );
Serverremoteobject. serverobject OBJ = (serverremoteobject. serverobject) handle. Unwrap ();
This method is actually the default constructor called. The objecthandle. Unwrap () method returns the encapsulated object.
Note: To use urlattriation, you must add using system. runtime. remoting. activation in the namespace;
V. Supplement of remoting Basics
As described above, a simple remoting program has been basically completed. This is a standard method to create a remoting program, but in actual development, what we encounter may be strange. If we only grasp one so-called "standard ", it is impossible to imagine that you can "Try it out and eat it all over the sky.
1. register multiple channels
In remoting, multiple channels can be created simultaneously, that is, different channels can be created based on different ports. However, remoting requires that the channel name must be different because it must be used as the unique identifier of the channel. Although ichannel has the channelname attribute, this attribute is read-only. Therefore, the method for creating channels described above cannot meet the requirements for registering multiple channels at the same time.
At this time, we must use the idictionary interface in system. Collection:
Register the TCP channel:
Idictionary tcpprop = new hashtable ();
Tcpprop ["name"] = "tcp9090 ";
Tcpprop ["Port"] = 9090;
Ichannel channel = new tcpchannel (tcpprop,
New binaryclientformattersinkprovider (),
New binaryserverformattersinkprovider ());
Channelservices. registerchannel (Channel );
Register an HTTP channel:
Idictionary httpprop = new hashtable ();
Httpprop ["name"] = "http8080 ";
Httpprop ["Port"] = 8080;
Ichannel channel = new httpchannel (httpprop,
New soapclientformattersinkprovider (),
New soapserverformattersinkprovider ());
Channelservices. registerchannel (Channel );
You can define different channel names in the name attribute.
2. Remote Object metadata relevance
Because remote objects are used on both the server and client, the common method is to generate two identical object DLL files and add references respectively. However, to ensure code security and reduce the client's relevance to remote object metadata, we need to modify this method. That is, remote objects are implemented on the server side, while metadata of these implementations is deleted on the client side.
Because of the different activation modes, the methods for creating objects on the client are also different, so the relevance of metadata should be separated into two cases.
(1) wellknown activation mode:
Implemented through interfaces. On the server side, interfaces and specific classes are provided, while on the client side, only interfaces are provided:
Public interface iserverobject
{
Person getpersoninfo (string name, string sex, int age );
}
Public class serverobject: marshalbyrefobject, iserverobject
{......}
Note: The names of the object Assembly generated on both sides must be the same. Strictly speaking, the namespace names must be the same.
(2) Client activation mode:
As mentioned above, for the client activation mode, whether the static method or the createinstance () method is used, the constructor must be called on the client to instantiate the object. Therefore, the remote object we provide on the client cannot only provide interfaces, but there is no class implementation. In fact, there are two ways to separate metadata from remote objects:
A. Use the wellknown activation mode to simulate the client activation mode:
The method is to use the "Abstract Factory" in the design pattern. The following class chart describes the overall solution:
We add Abstract Factory interfaces and implementation classes to remote objects on the server:
Public interface iserverobject
{
Person getpersoninfo (string name, string sex, int age );
}
Public interface iserverobjfactory
{
Iserverobject createinstance ();
}
Public class serverobject: marshalbyrefobject, iserverobject
{
Public Person getpersoninfo (string name, string sex, int age)
{
Person = new person ();
Person. Name = Name;
Person. Sex = sex;
Person. Age = age;
Return person;
}
}
Public class serverobjfactory: marshalbyrefobject, iserverobjfactory
{
Public iserverobject createinstance ()
{
Return new serverobject ();
}
}
Then, only the factory interface and the original object interface are provided in the remote object of the client:
Public interface iserverobject
{
Person getpersoninfo (string name, string sex, int age );
}
Public interface iserverobjfactory
{
Iserverobject createinstance ();
}
We use wellknown activation mode to register remote objects on the server:
// Transfer object;
Remotingconfiguration. registerwellknownservicetype (
Typeof (serverremoteobject. serverobjfactory ),
"Servicemessage", wellknownobjectmode. singlecall );
Note that the registration is not a serverobject class object, but a serverobjfactory class object.
Client:
Serverremoteobject. iserverobjfactory serverfactory =
(Serverremoteobject. iserverobjfactory) activator. GetObject (
Typeof (serverremoteobject. iserverobjfactory ),
"TCP: // localhost: 8080/servicemessage ");
Serverremoteobject. iserverobject serverobj = serverfactory. createinstance ();
Why is this a simulation of the client activation mode? From the perspective of the activation method, we use the singlecall mode to activate the object. However, activation is not a remote object to be passed, but a factory object. If the client wants to create a remote object, it should also be obtained through the createinstance () method of the factory object. This method is called on the client. Therefore, the implementation method is equivalent to the client activation mode.
B. Use Substitution classes to replace metadata of remote objects
In fact, we can use a trick to cheat remoting. The alternative class mentioned here is trick. Since the service is provided, the implementation details of the remote object passed by remoting are of course placed on the server side. However, to put a copy of the object on the client, it is helpless because the client must call the constructor. Since the specific implementation is on the server side and in order to be instantiated on the client side, it is better to achieve this on the client side. As for the Implementation Details, you don't have to worry about it.
If the remote object has a method, the server provides the method implementation, and the client provides this method. As for the implementation, you can throw an exception, or return a null value. If the method returns void, it can be null. The key is that this method is required for this client class object. The implementation of this method is similar to the declaration of the method, so I say it is a trick. If the method is used, the constructor is also used.
It is more intuitive to use code to describe this "conspiracy:
Server:
Public class serverobject: marshalbyrefobject
{
Public serverobject ()
{
}
Public Person getpersoninfo (string name, string sex, int age)
{
Person = new person ();
Person. Name = Name;
Person. Sex = sex;
Person. Age = age;
Return person;
}
}
Client:
Public class serverobject: marshalbyrefobject
{
Public serverobj ()
{
Throw new system. notimplementedexception ();
}
Public Person getpersoninfo (string name, string sex, int age)
{
Throw new system. notimplementedexception ();
}
}
Comparing the client and server, the client method getpersoninfo () has no specific implementation details, but throws an exception. Or directly write the statement return NULL, so OK. We call this client class an alternative class for remote objects.
3. Using configuration files
The preceding method uses code to set the server Uri, port, and activation mode. In fact, we can also set it using the configuration file. This is advantageous because the configuration file is an XML document. If you need to change the port or other, you do not need to modify the program and re-compile it. Instead, you only need to change the configuration file.
(1) server configuration file:
& Lt; configuration & gt;
& Lt; system. runtime. remoting & gt;
& Lt; Application name = "serverremoting" & gt;
& Lt; Service & gt;
& Lt; wellknown mode = "Singleton" type = "serverremoteobject. serverobject" objecturi = "servicemessage"/& gt;
& Lt;/service & gt;
& Lt; channels & gt;
& Lt; Channel ref = "TCP" Port = "8080"/& gt;
& Lt;/channels & gt;
& Lt;/Application & gt;
& Lt;/system. runtime. remoting & gt;
& Lt;/configuration & gt;
In the client activation mode, change wellknown to activated and delete the mode attribute.
Put the configuration file in the application folder of the server program and name it serverremoting. config. Then the preceding server-side program can directly use this statement:
Remotingconfiguration. Configure ("serverremoting. config ");
(2) Client configuration file
If the client activation mode is used, the modification is the same as the above. The remotingconfiguration. Configure () method is also used to call the configuration file stored on the client.
The configuration file can also be stored in machine. config. If the client program is a Web application, it can be placed in Web. config.
4. Start/close a specified Remote Object
Remoting does not provide a method similar to unregisterwellknownservicetype (), that is, once a remote object is registered, if the channel is not closed, the object will remain in the channel. As long as the client activates this object, an object instance is created. If remoting only transmits one remote object, this is not a problem. You can close the channel. What if multiple remote objects are transmitted? What should I do if I want to disable the specified remote object? What should I do if I need to start it again after it is disabled?
We noticed that the remoting provides the marshal () and disconnect () methods, and the answer is here. The marshal () method is to convert the externalbyrefobject class object to an objref class object, which stores all the relevant information required to generate a proxy to communicate with remote objects. In this way, the instance can be serialized for transmission between application domains and through the network, and the client can call it. The disconnect () method disconnects a specific instance object from the channel.
The method is as follows:
First, register the channel:
Tcpchannel channel = new tcpchannels (8080 );
Channelservices. registerchannel (Channel );
Start the service:
Instantiate a remote object on the server first.
Serverobject OBJ = new serverobject ();
Then, register the object. Note that remotingconfiguration. registerwellknownservicetype () is not used here, But remotingservices. Marshal () is used ():
Objref objrefwellknown = remotingservices. Marshal (OBJ, "servicemessage ");
If you want to deregister an object, then:
Remotingservices. Disconnect (OBJ );
Note that the disconnect class object must be the previously instantiated object. For this reason, we can create a specified remote object as needed. When the remote object is disabled, the object instantiated before disconnect is used.
As for client calls, the methods in the wellknown mode are the same as those in the previous method, and are still obtained through activator. GetObject. But from the implementation code point of view, we will notice a problem, because the server side explicitly instantiates the remote object, no matter how many clients are there, whether it is the same, they call the same remote object. Therefore, we call this method the simulated Singleton mode.
Client activation mode
We can also simulate the client activation mode through Marshal () and disconnect. First, let's review the "remote object metadata Relevance" section. In this section, I talked about using the design pattern "Abstract Factory" to create an object instance, use singlecall mode to simulate the client activation mode. Think carefully about the singleton model. Is the answer coming soon?
In the "simulated Singleton" mode, we perform marshal on a specific remote object instance to allow the client to obtain reference information for this object. In this case, we use the abstract factory to provide interfaces and the factory class to create remote objects. Then we create a factory instance on the server side. Then perform the marshal operation on the factory instance. When the client obtains an object, it does not obtain a specific remote object, but a specific factory object. Then, call the createinstance () method to create a specific remote object instance. At this time, for multiple clients, the same factory object is called; however, the remote object is created on each client, so for the remote object, it is activated by the client, different objects are created.
To start/close a specified object, you only need to use the disconnet () method to deregister the factory class object.
Vi. Summary
Microsoft. NET remoting is really profound and profound. The content of remoting is not what I can do in this article, nor is it what I can grasp by beginners of remoting. Wang Guowei wrote in his book "The Word of man": The Ancient and Modern University of great business, the question, will go through three levels. "Last night, the west wind withered green trees and tall buildings, hoping to go all the way to heaven ." This is also the first realm. "I don't regret it when I get out of my clothes, so I am worn out ." This second realm is also true. "Looking for him in the crowd, suddenly looking back, that person is in the dark ." This third realm is also true. For example, to describe my learning about remoting, when I was still in a "tall building, looking at the path of Heaven", I could say that I have never been in the room.
Maybe you need to get "clothes gradually wider" and learn remoting and never regret it. You can just "Look Back.