Introduction
Microsoft® .NET Remoting provides a framework that allows objects to interact with another object via an application domain. This framework provides a variety of services, including activation and survival support, and communication channels responsible for messaging with remote applications. The formatting program is used to encode and decode it before the message is transmitted through the channel. Applications can use binary encoding in applications that are in terms of performance, and XML encoding is used in applications that need to interact with other remote processing frameworks. All XML encoding uses the SOAP protocol when transmitting messages from an application domain to another. For security considerations, remote processing provides a large number of hooks such that the security receiver can access messages and serializations before messaging over channels.
Typically, if there is no support for the underlying framework, it will be very troublesome to manage the life of the remote object. .NET Remoting provides a number of available survival models, which are divided into two categories:
Client Activation Object Server Activation Object
The client activation object is controlled by the lease-based survival manager, which ensures that the rental expiration time can be reclaimed. For server activation objects, developers can select "Single Turn" mode or "single element" mode.
Remote object
One of the main purposes of any remote processing framework is to provide the necessary infrastructure to hide the complexity of the remote object call method and the return result. Any object outside the calling application domain, even if it is executed on the same computer, it is considered a remote object. In the application domain, the original data type is passed, and all objects are passed by reference. Because local object references are valid only within the application domain for creating objects, they cannot be passed to remote methods in this way, or returned from remote method calls. All local objects that must span the application domain must be passed by value, and should be tagged with the [Serializable] custom property, otherwise they must implement the iSerializable interface. When the object is passed as a parameter, the framework seizes and transmits the object to the target application domain, and the object will be re-constructed in the target application domain. A local object that cannot be serialized will not be passed to other application domains, and thus cannot be processed remotely.
You can turn any object to a remote object by exporting an object from a MARSHALBYREFOBJECT. When a client activates a remote object, it will receive the agent of the remote object. All operations for the agent are properly reopened so that the remote processing infrastructure can be properly intercepted and forwarded. Although this reordbing has some effects, the JIT compiler and execution engine (EE) have been optimized, and unnecessary performance loss can be prevented when the agent and remote object reside in the same application domain. If the proxy and remote objects are not in the same application domain, all methods in the stack call parameters are converted to messages and transferred to remote application domains, which will be converted to the original in the remote application domain. Stack frame, and this method call will also be called. The same process is also used when the result is returned from the method call.
Proxy object
The proxy object is created when the client activates the remote object. As a representative of the remote object, the proxy object ensures that all calls to the agent can forward to the correct remote object instance. In order to accurately understand the working mode of the agent object, we need to study them more deeply. When a client activates a remote object, the framework will create a local instance of the TransparentProxy class (this class contains list of all classes and the interface method of the remote object). Because the TransparentProxy class is registered with CLR when creating, all method calls on the agent are intercepted when they are running. At this time, the system will check the call to determine if it is a valid call for the remote object, and whether the instance of the remote object is located in the same application domain with the agent. If the object is in the same application domain, the simple method call will be routed to the actual object; if the object is in a different application domain, package it to the iMessage object and forwarded by calling the invoke method in the stack. In the REALPROXY class. Such (or its internal implementation) is responsible for forwarding messages to remote objects. The TransparentProxy class and the REALPROXY class are created in the background after the remote object is activated, but only TransparentProxy returns to the client. To better understand these proxy objects, we need to briefly introduce Objref. A detailed description of the Objref is activated in the section. The following scheme briefly illustrates the association method of Objref with these two proxy classes. However, please note that this is only an extremely summary of the process; depending on the object is a client activation object or the server activates the object, and they are a single element object or a single call object, the process will vary.
Remote objects are registered in the application domain of remote computers. Remote objects are sealed to generate Objref. ObjRef contains all information required to locate and access remote objects from the network, including: the enhancement name of the class, the hierarchy of the class (its parent class), the name of all interfaces, objects URI, and all Details of the registered available channels. When receiving a request for a remote object, the Remote Processing Framework uses the object URI to retrieve the Objref instance created for the object. The client activates the remote object by calling the New or an Activator function (such as CREATEINSTANCE). For server activation objects, the TransparentProxy of the remote object will be generated and returned to the client in the client application domain, and no remote call is not performed. The remote object will be activated only when a method of calling a remote object is called. This program is obviously not suitable for client activation objects because the client wants the framework only to activate the object only when the request is obtained. When the client calls a activation method, a activation agent will be created on the client and will use the URL and the object URI as an endpoint to initialize a remote call on the server's remote activator. The remote activation activates the object, then the OBJREF flows to the client and is canceled to generate a returned TransparentProxy. The OBJREF is analyzed during canceling the process to extract the method information of the remote object, and also creates TransParentProxy and RealProxy objects. Before using the CLR to register TransparentProxy, the analytical OBJREF content is added to the inside table of TransparentProxy.
TransparentProxy is an instead and extended internal class, while REALPROXY and OBJREF classes belong to public classes, which can be extended and customized when necessary. Since the REALPROXY class can handle all function calls of the remote object, it is an ideal method for performing operations such as load balancing. When invoking invoke, the class exported from RealProxy can obtain load information of the server in the network and route the call to the appropriate server. Simply request a Messagesink for the desired Objecturi, and call SyncProcessMessage or AsyncProcessMessage to forward the call to the desired remote object. When the call is returned, the return parameter is pushed back to the stack by calling the RemotingServices class with PropagateMedToProxy. The following code snippet shows how to use the exported REALPROXY class.
MyRealProxy Proxy = New MyRealProxy (TypeOf (foo));
Foo Obj = (foo) proxy.gettransparentProxy ();
Int result = obj.callsomethod ();
The transparentProxy acquired in the above example can be forwarded to another application domain. When the second client attempts to call a method on the agent, the remote processing framework will try to create an instance of the MyRealProxy class, and if the assembly is available, all calls will route to this instance. If the assembly is unavailable, call the route to the default remote REALPROXY.
Objref can be easily customized by providing alternatives for the default Objref property TypeInfo, EnvoyInfo, and ChannelInfo. The following code shows how to customize:
Public clas objref {
Public Virtual IRemotingTypeInfo TypeInfo
{
Get {return typeInfo;
Set {typeInfo = value;}
}
Public Virtual IenvoyInfo EnvoyInfo
{
Get {return envoyinfo;}
Set {envoyinfo = value;
}
Public Virtual IchannelInfo ChannelInfo
{
Get {return channelinfo;}
Set {ChannelInfo = Value;}
}
}
aisle
Channels are used to transfer messages between remote objects. When the client calls a method on a remote object, the parameters associated with the call and other details are transmitted to the remote object via channels. Any result of the call will return to the client in the same manner. The client can select any of the channels registered in "Server" to implement communication between the remote object, so developers can freely select the most suitable channels. Of course, you can also customize any existing channels or create new channels using other communication protocols. Channel selection follows the following rules:
The remote processing frame must be registered at least one channel before being able to call the remote object. Channel registration must be performed before the object registration. The channel is registered according to the application domain. There are multiple application domains in a process. When the process ends, all channels registered with the process will be automatically cleared. The channels that register for listening to the same port are illegal. Even if the channel is registered in the application domain, the channels on the same computer cannot be registered with different application domains on the same computer. The client can communicate with the remote object with any registered channel. The remote processing framework ensures that the object is connected to the correct channel when the client tries to connect to a remote object. The client is responsible for calling the RegisterChannel class of the ChannelService class before trying to communicate with the remote object.
All channels are exported by iChannel and implement iChannelReceiver or iChannel Sergence based on the use of channels. Most channels have both a receiver interface and a transmitter interface that enables them to communicate in both directions. When the client calls a method on the agent, the remote processing framework intercepts the call and converts it to the RealProxy class (or an instance implementing the REALPROXY class). RealProxy forwards messages to the message receiver for processing. The message receiver is responsible for establishing a connection between the channel registered with the remote object, and transmits the message from the scheduling location to the remote object itself through the channel (in different application domains). After activating a remote object, the client selects the channel by calling the CreateMessageSink on the selected channel and retrieves the message receiver that can communicate with the remote object. An easy confusion of the remote processing framework is the relationship between the remote object and the channel. For example, if the SingleCall remote object is only activated only when called, how do this object listens to the client to connect?
Some answers are the fact that the remote object does not have its own channel, but a shared channel. The server application as a remote object host must register the object to be disclosed by the remote processing framework and the required channel. The registered channel will automatically start listening to the customer request at the specified port. After registering the remote object, you will create an OBJREF for the object and store it in the table. When a request is received upon a request, the remote processing frame checks the message to determine the target object, while checking the object reference table to locate the reference in the table. If an object reference is found, retrieve the frame target object from the table or activate it if necessary, and then the frame will forward to the object. For synchronous calls, connections from the client are maintained during the message call. Because each client connection is processed on its own thread, a channel can serve multiple clients at the same time.
Safety is an important issue when generating business applications. To meet business requirements, developers must be able to add security features such as authorization or encryption to remote methods. In order to achieve this, developers can customize channels to control them on the actual message transport mechanism between the remote object. All messages must flow through SecuritySink, TransportSink, and Formattersink before transferring to remote applications, and these messages are passed to the same receiver after the remote application.
HTTP channel
The HTTP channel uses the SOAP protocol to transfer messages with remote objects. All messages are converted to an XML format when all messages are formatted and serialized, and the desired SOAP header is also added to the stream. You can also specify binary formatting procedures that can generate binary data streams. The data flow will then transfer to the target URI using the HTTP protocol.
TCP channel
The TCP channel uses the binary format to divide all message sequences into binary streams and transfer them to the target URI using the TCP protocol.
activation
Remote Processing Framework supports server activation and client activation of remote objects. Do not require remote objects to maintain any status between method calls, usually use the server activation. Server activation also applies to multiple client calls to the same object instance, and the object is maintained between function calls. On the other hand, the client activation object is instantiated from the client, and the client manages the survival of the remote object by using a lease-based private system.
All remote objects must be registered with a remote processing framework before accepting client access. Object registration is generally done by host applications. The host application will start, register one or more channels using ChannelServices, register one or more remote objects with RemotingServices, and then wait to terminate. Note that the registered channels and objects can only be used when they are used to register their processes. If you exit this process, you will automatically remove all channels and objects it registered from the remote processing service. When registering a remote object in a frame, you need the following four information: The name of the assembly containing the class. Type name of the remote object. The object URI that will be used when the client is positioned. Server activates the desired object mode. This mode can be SingleCall or Singleton.
Remote objects can be registered in two ways: call registerWellkNowNType, passed the above information as parameter; or store the above information in the configuration file, then call configureReming and transfer the name of the configuration file as a parameter. The above two methods are the same, so you can use any of them to register the remote object. Of course, the latter approach is more convenient because there is no need to recompile the host application to change the contents of the configuration file. The following code snippet shows how to register the HelloService class as a SingleCall remote object.
RemotingServices.RegisterWellkNowntype
"Server",
"Samples.HelloServer",
"Sayhello",
WellknownObjectMode.singlecAl1;
Among them, "server" is the name of the assembly, HelloServer is the name of the class, and Sayhello is an object URI.
After registering the remote object, the framework creates an object reference for the object and extracts the necessary metadata associated with the object from the assembly. Subsequently, this information stores with the URI and the assembly name in the object reference (the object reference will be written into a remote processing frame table for tracking the registered remote object). Note that the registration process does not instantiate the remote object itself in addition to a method on the client attempts to call the object or activates the object from the client.
Now, any client that knows the object URI can use the ChannelServices registration channel and call new, getObject or createInstance activation object, thereby obtaining an agent of the object. The following code snippet shows an example of this operation:
ChannelServices.RegisterChannel (New Tcpchannel);
HelloServer Obj = (HelloServer) Activator.getObject
TypeOf (Samples.helloServer), "TCP: // localhost: 8085 / Sayhello");
Among them, "TCP: // localhost: 8085 / shorthello" means that we want to use the TCP protocol on port 8085 to connect to a remote object located at the SayHello endpoint. When compiling the client code, the compiler clearly requires type information about the HelloServer class. This information can be provided by one of the following methods:
Provides a reference to the assembly of the HelloService class. Spread the remote object into implementation and interface classes and reference these interfaces when compiling the client. Use the SOAPSUDS tool directly from the endpoint to extract the desired metadata. This tool will be connected to the supplied endpoint, extract metadata, and generate an assembly or source code that can be used to compile the client.
GetObject or New can be used for server activation objects. Note that the object will not be instantiated when using these two calls, which does not generate any network calls. The framework obtains sufficient information required to create a proxy from metadata, but is not connected to the remote object. Network connections are only established when a client calls a proxy. When the arrival server is called, the frame will extract the URI from the message to check the remote processing framework to locate the object references that match the URI, and then instantiate the object when necessary, and forward the method call to the object. If the object is registered as SingleCall, the object will be canceled after completing the method call. A new instance is created each time you call a method. The only difference between GetObject and New is that the former allows the URL to be specified as a parameter, and the latter gets URLs from the configuration. CREATEINSTANCE or New can be used for client activation objects. Both allow the use of parameters to instantiate the object. The survival of the client activation object is controlled by the rental service provided by the remote processing framework. The content of the object lease is described in the next section.
Object rental survival
Each application domain contains a lease manager for managing its lease. All leases are regularly checked to determine if the lease has expired. If the rent expires, one or more initiators of the lease will be called so that they have the opportunity to update the rent. If all the initiats are not prepared to update the rent, the lease manager will delete the rent and reclaim the object as garbage. The lease manager maintains the list of leases in order of the remaining leased time. The shortest rental rental is ranked at the top of the list.
Rentality can implement an ILEase interface and store an attribute set to determine the updated policies and methods. You can also use calls to update rent. Each time you call the method on the remote object, the rental time is set to the current Leasetime maximum plus renewoncalltime. When LeaseTime is about to expire, the initiator will be required to update the rent. Because we sometimes meet the network unstable, the rental initiator may not be found. To ensure that the invalid object is not left on the server, each lease has a sponsorshiptimeout. This value specifies the length of time waiting for leased initiators before lease termination. If sponsershiptimeout is zero, CurrentleaseTime will be used to determine the expiration time of the lease. If the value of the currentleasetime is zero, the rent will not expire. Configuration or API can be used to replace the default value of InitialLeasetime, SponsorshipTimeout, and RenewonCallTime.
The lease manager maintains a list of initiators from large to small storage (they implement the ISPonsor interface) by initiating time. When you need to call the initiator to update the lease time, the lease manager will start to update the rental time from the top of the list to one or more initiators. The initiator at the top of the list indicates the longest rental update for its previously requested. If the initiator does not respond within the SponsorshipTimeout time period, it will be removed from the list. This object rent can be obtained by calling getLifetimeService and uses an object to use as a parameter. This call is a static method of the RemotingServices class. If the object is inside the application domain, the call to the parameter is the local reference of the object, and the returned lease is also a local reference for the rent. If the object is remote, the agent will be passed as a parameter and return to the call to the transparent agent.
Objects can provide your own rental and control your life. They complete this operation by replacing the Initializer fiPetimeService method on MarshalByrefObject, as shown below:
Public class foo: MarshalbyrefObject {
Public override Object InitializelifetimeService ()
{
Ilease Lease = (ilease) Base.initializelifetimeService (); if (Lease.currentState == LeaseState.Initial) {
Lease.initialLeasetime = Timespan.fromminutes (1);
Lease.sponsorshipTimeout = Timespan.fromminutes (2);
Lease.renewoncalltime = timeespan.fromseconds (2);
}
Return Lease;
}
}
The lease properties can only be changed if the lease is in an initial state. The implementation of the initializelifetimeservice usually invokes the corresponding method of the base class to retrieve the existing rental of the remote object. If the object has never been encapsulated before this, the returned rent will be in its initial state and can set the rental attribute. Once the object is sealed, the rent will become activated from the initial state and ignore any attempt to initialize the rental attribute (but there is an exception). InitializelifetimeService will be called when you activate the remote object. A list of rental initiators can be provided by activating calls, and other initiators can be added to the list at any time when the lease is active.
You can extend the rental time in the following manner:
The client can call the Renew method on the Lease class. Rent can request Renewal to a sponsor. When the client calls a method on the object, the RenewonCall value automatically updates the rent.
Once the rent is expired, its internal state will be changed from Active to Expired, and no longer make any call to the initiator, the object will be reclaimed as garbage. In general, if the initiator is dispersed on the web or is behind a firewall, it will encounter difficulties when the remote object calls the initiator. Therefore, the initiator does not have to be in the same location as the client, as long as the remote object can access, it can be anywhere on the network.
By leaseing to manage the survival of the remote object as an alternative to the reference count, because the performance of the network connection is unreliable, the reference count is complex and inefficient. Although some people will persist that the survival period of the remote object is longer than the time required, the rent reduces the busyness of the network with reference counting and connection customers, will become a very popular solution.
to sum up
To provide perfect, you can meet the remote processing frameworks of most business applications, even if you can do it, it will inevitably be very difficult. Microsoft provides a framework capable of expanding and customizing as needed, a key step in the correct direction.
Appendix A: Example of remote processing using TCP channels
This appendix shows how to write a simple "Hello World" remote application. The client passes a string to the remote object, which is attached to the word "hi there" to the string and returns the result to the client.
Save this file as server.cs. Here is the code of the server:
Using system;
Using system.runtime.remoting;
Using system.runtime.remoting.channels.tcp;
Namespace Remotingsamples {
Public class helloserver: ihello {
Public static int main (string [] args) {
Tcpchannel CHAN = New TcpChannel (8085);
ChannelServices.RegisterChannel (CHAN);
RemotingServices.RegisterWellkNowntype
"Server", "Remotingsamples.helloServer", "Sayhello", WellkNownObjectMode.singlecAll); System.Console.writeline ("Please press
System.console.readline ();
Return 0;
}
Public HelloServer ()
{
Console.writeline ("HelloServer is activated";
}
~ HelloServer ()
{
Console.writeLine ("Object has been cleared");
}
Public Forwardme Hellomethod (Forwardme Obj)
{
Console.writeline ("Hello.Hellomethod: {0}", name);
Return "hi there" name;
}
}
}
Save this code as client.cs:
Using system;
Using system.runtime.remoting;
Using system.runtime.remoting.channels.tcp;
Namespace Remotingsamples {
Public Class Client
{
Public static int main (String [] ARGS)
{
TCPCHANNEL CHAN = New TCPChannel ();
ChannelServices.RegisterChannel (CHAN);
ForwardMe param = new forwardme ();
HelloServer Obj = (HelloServer) Activator.getObject
TypeOf (Remotingsamples.HelloServer), "TCP: // localhost: 8085 / Sayhello");
IF (obj == null) System.Console.writeline ("Unable to locate server");
Else {
Console.WriteLine ("value" param.getValue ());
Forwardme after = Obj.hellomethod (param);
Console.WriteLine ("The value after the call is" after.getValue ());
}
Return 0;
}
}
}
Here is Makefile:
All: Server.exe Client.exe Share.dll
Share.dll: Share.cs
CSC / Debug / Target: library /out:share.dll Share.cs
Server.exe: Server.cs
CSC / Debug /R :share.dll /r :system.runtime.remoting.dll Server.cs
Client.exe: Client.cs Server.exe
CSC / Debug /R :share.dll /r:Server.exe /R :system.Runtime.Remoting.dll Client.cs
Clean:
@Del server.exe client.exe * .pdb * ~ *. * ~
Appendix B: Example of remote processing using an HTTP channel
Save this file as server.cs. Here is the code of the server:
Using system;
Using system.Runtime.Remoting; use system.runtime.remoting.channels.http;
Namespace Remotingsamples {
Public class helloserver: ihello {
Public static int main (string [] args) {
HTTPCHANNEL CHAN = New httpchannel (8085);
ChannelServices.RegisterChannel (CHAN);
RemotingServices.RegisterWellkNowntype
"Server", "Remotingsamples.helloServer", "Sayhello", WellkNownObjectMode.singlecaLL);
System.Console.writeline ("Please press
System.console.readline ();
Return 0;
}
Public HelloServer ()
{
Console.writeline ("HelloServer is activated";
}
~ HelloServer ()
{
Console.writeLine ("Object has been cleared");
}
Public Forwardme Hellomethod (Forwardme Obj)
{
Console.writeline ("Hello.Hellomethod: {0}", name);
Return "hi there" name;
}
}
}
Save this code as client.cs:
Using system;
Using system.runtime.remoting;
Using system.runtime.remoting.channels.http;
Namespace Remotingsamples {
Public Class Client
{
Public static int main (String [] ARGS)
{
HTTPCHANNEL CHAN = New httpchannel ();
ChannelServices.RegisterChannel (CHAN);
ForwardMe param = new forwardme ();
HelloServer Obj = (HelloServer) Activator.getObject
TypeOf (Remotingsamples.helloServer), "http:// localhost: 8085 / selfhello");
IF (obj == null) System.Console.writeline ("Unable to locate server");
Else {
Console.WriteLine ("value" param.getValue ());
Forwardme after = Obj.hellomethod (param);
Console.WriteLine ("The value after the call is" after.getValue ());
}
Return 0;
}
}
}
Here is Makefile:
All: Server.exe Client.exe Share.dll
Share.dll: Share.cs
CSC / Debug / Target: library /out:share.dll Share.cs
Server.exe: Server.cs
CSC / Debug /R :share.dll /r :system.Runtime.Remoting.dll Server.csclient.exe: Client.cs Server.exe
CSC / Debug /R :share.dll /r:Server.exe /R :system.Runtime.Remoting.dll Client.cs
Clean:
@Del server.exe client.exe * .pdb * ~ *. * ~