ArticleDirectory
- 1. Basic concepts of application domains
- 2. Basic operations on application domains
- 3. Create an object in the default application domain
- 4. Create an object in the new application domain
- 5. Proxy and sending)
- 6. Example of sending and referencing messages
- 7. Customer application (domain), server assembly, Host application (domain)
Introduction
Distributed applications with the increasing popularity of the Internet and the increasing speed of network transmissionProgramIs an important direction of software development. In. net, we can use web service or remoting technology to build distributed applications (in addition to the new generation of WCF, Windows Communication Foundation ). This article briefly introduces some basic concepts of remoting, including application domain, remoting architecture, passed value by value, and passed reference by reference) remote Method callback and host programs in Windows Service and IIS respectively. Finally, we will introduce the lifetime management of remote objects.
Understanding the basic concepts of remoting1.
. Many of the concepts in net are interlocking. If a knowledge point is not mastered (apply the term "precursor node" in the data structure, this is the "precursor knowledge point "), if you want to understand the problems you are currently facing, you will often encounter some obstacles and cannot go further, or you may not understand them thoroughly (you can do this, I don't know why. If it is only an emergency, it must be applied quickly ). To better understand remoting, we 'd better first look at remoting's precursor knowledge-application domain.
We know all.. NET applications run in the managed environment (managed environment), but the operating system only provides processes for running, while processes only provide basic memory management, it doesn't know what hosting is.Code. Therefore, the managed code can also be said to be the. Net program we created and cannot directly run in the operating system process. To make managed code run on an unmanaged process, you need an intermediary who can run on an unmanaged process, it also provides the runtime environment for the managed code. This intermediary isApplication domain(Application domain, abbreviated as APP domain ). Therefore, our. net programs, whether Windows Forms, web forms, console applications, or an assembly, always run in an app domain.
If there is only one class library assembly (. dll file), a process cannot be started (it is not an executable file ). Therefore, to create a process, you need to load an executable Assembly (the. exe file, such as the windows window program control platform application ). When the executable assembly is loaded,. NET will create a new application domain in the current process, calledDefault Application domain. Only one default application domain is created in a process. The application domain name is the same as the Assembly name. By default, the application domain cannot be detached and the process in which the application resides is released.
Then how does the application domain provide a hosted environment? Simply put, the application domain only allows the Assembly it loads to access the services provided by. Net runtime. These services include managed heap, garbage collector, and JIT compiler. net underlying mechanism, these services themselves (they constitute. net runtime) is implemented by an unmanaged C ++.
A process can contain multiple application domains, and an application domain can contain multiple assemblies. For example, if our asp.netapplication runs in the aspnet_wp.exe(iis5.000000000w3wp.exe (iis6.0) process, and IIS usually creates multiple sites, is an independent process created for each site? . There are at least two advantages: 1. creating multiple app domains in a process requires much less system overhead than creating and running multiple processes; 2. Implementing error isolation, if a site crashes due to a fatal error, it will only affect the application domain where it is located, rather than the application domain where other sites are located.
2. Basic operations on application domains
In. net, the application domain is encapsulated as the appdomain class. This class provides various operations for the application domain, including loading the Assembly, creating objects, and creating application domains. In general programming, we almost never need to operate on the appdomain. Here we only look at a few common operations that will be used in this article to help us understand and debug remoting:
1. to obtain the application domain where the currently running code is located, you can use the static attribute currentdoamin of the appdomain class to obtain the application domain where the current code is located, or use the static method getdomain () of the thread class (), obtain the application domain of the current thread:
AppdomainCurrentdomain = appdomain. currentdomain;
AppdomainCurrentdomain =Thread. Getdomain ();
Note:A thread can access all application domains contained in a process, because although application domains are isolated from each other, they share a managed heap ).
2. Get the name of the application domain, use the read-only attribute of the appdomain instance, friendlyname:
StringName = appdomain. currentdomain. friendlyname;
3. Create an application domain from the current application domain. You can use the createdomain () static method and input a string as the name of the new application domain (that is, set the friendlyname attribute ):
AppdomainNewdomain = appdomain. createdomain ("New Domain");
4. Create an object in the application domain. You can use the createinstanceandunwrap () or createinstance () method of the appdomain instance. The method contains two parameters. The first parameter is the assembly of the type, and the second parameter is the full name of the type (these two methods will be detailed later ):
DemoclassOBJ = (democlass) appdomain. currentdomain. createinstanceandunwrap ("Classlib", "classlib. democlass");
ObjecthandleObjhandle = appdomain. currentdomain. createinstance ("Classlib", "classlib. democlass");
DemoclassOBJ = (democlass) objhandle. Unwrap ();
5. Determine if it is the default application domain:
Newdomain. isdefaappappdomain ()
3. Create an object in the default application domain
Before we start, let's clarify a concept. Please refer to the following code:
Class Program{
Static Void Main (String[] ARGs ){
MyclassOBJ =New Myclass();
OBJ. dosomething ();
}
}
In this case, obj isTarget customers, Program isCustomer ProgramNo matter where obj is located.
Next let's look at a simple example. We use the appdomain-based operation mentioned above to create an object in the current default application domain. First, create a class library project classlib, and then create a class democlass in it. The instance of this class is the object we will create:
NamespaceClasslib {
Public Class Democlass{
Private IntCount = 0;
PublicDemoclass (){
Console. Writeline ("\ N ======DomoclassConstructor ======");
}
Public Void Showcount ( String Name ){
Count ++;
Console . Writeline ( "{0}, the countIs{1 }." , Name, count );
}
// Print the application domain of the object
Public Void Showappdomain (){
Appdomain Currentdomain = appdomain. currentdomain;
Console . Writeline (currentdomain. friendlyname );
}
}
}
Next, create a console application, name the project consoleapp, reference the class library project classlib created above, and add the following code:
Class Program{
Static Void Main (String[] ARGs ){
Test1 ();
}
// Create an object in the current appdomain
Static Void Test1 (){
Appdomain Currentdomain = appdomain. currentdomain; // Obtain the current application domain
Console . Writeline (currentdomain. friendlyname ); // Print the name
Democlass OBJ;
//OBJ =New Democlass() // General object Creation Method
// Create an object in the default application domain
OBJ = (democlass) currentdomain. createinstanceandunwrap ("Classlib", "classlib. democlass");
OBJ. showappdomain ();
OBJ. showcount ( "Jimmy" );
OBJ. showcount ( "Jimmy" );
}
}
Run this code and the result is:
Leleapp.exe
========DomoclassConstructor ======
Leleapp.exe
Jimmy, the countIs1.
Jimmy, the countIs2.
It works well now and everything is fine. You may want to ask, what is the significance of using this method to create an object? What is the difference between using createinstanceandunwrap () to create an object and using new democlass () to create an object? Before answering this question, let's look at another situation:
4. Create an object in the new application domain
Let's take a look at how to create a new appdomain, and then create a democlass object in this new appdomain. You may think that this is not simple. It is okay to change the above example slightly:
// Create an object in the new appdomain
Static VoidTest2 (){
AppdomainCurrentdomain = appdomain. currentdomain;
Console. Writeline (currentdomain. friendlyname );
// create a new application domain-newdomain
appdomain newdomain = appdomain. createdomain ( "newdomain" );
democlass OBJ;
// create an object in the new application domain
OBJ = (democlass) newdomain. createinstanceandunwrap ( "classlib", "classlib. democlass ");
obj. showappdomain ();
obj. showcount ( "Jimmy" );
obj. showcount ( "Jimmy" );
}
Then we run Test2 () in the main () method, but an exception is returned:The type "classlib. democlass" is not marked as serializable.Before marking classlib. democlass as serializable, let's think about why this exception occurs. Let's look at the code for declaring the OBJ type:Democlass objects are declared. Then, we can see that the type instance (object itself) is created in the newly created application domain-newdomain through newdomain. createinstanceandunwrap.This leads to an embarrassing situation:The object is referenced in the current application domain (appconsole.exe), and the object itself (type instance) is located in the newly created application domain (newdomain ).As we mentioned above, appdomain is isolated by default. We cannot directly reference objects in another application domain in one application, so an exception is thrown here.
How can this problem be solved? Follow the exception prompt: "classlib. democlass" is not marked as serializable. Then we mark it as serializable, does it solve this problem? We can try to mark classlib. democlass as serializable:
[Serializable]
Public Class Democlass{/* Omitted */}
Then run the program again and find that the program runs normally and is exactly the same as the above output:
Leleapp.exe
========DomoclassConstructor ======
Leleapp.exe
Jimmy, the countIs1.
Jimmy, the countIs2.
Then, we find that the object created in the application domain newdomainis in leleapp.exe, that is, the current application domain. This illustrates a problem:When we mark the object as serializable and then perform the above operations, the object itself has been passed to the local application domain by another application domain (remote.Because it requires that the object be marked as serialized, it is difficult to think that the specific method is to create an object remotely, serialize the object, then pass the object, and perform local deserialization, finally, restore the object.
5. Proxy and envelope aling 5.1 proxy)
Now let's go back to the example of creating an object in the default application domain in section 3rd. Through the Test2 () example above, it is easy to understand why test1 () does not throw an exception,Because the objobject is stored in consoleapp.exe in the current application domain, there is no cross-application domain access problem and no exception is thrown.So what are the differences between using the following two methods to create objects in the current application domain?
DemoclassOBJ =New Democlass();// Method 1
DemoclassOBJ = (democlass) newdomain. createinstanceandunwrap ("Classlib", "classlib. democlass"); // Method 2
When we use the first method, we create an object in the managed heap and directly reference this object. In the second method, we actually create two objects: we created this object in newdomain, copied and serialized the object status, and thenMailIn leleapp.exe (client application domain), re-create the object, restore the object status, and create the object.Proxy. .
Two new names, proxy and mail, are displayed in the preceding description. Now let's explain the proxy,Proxy)Provides the same interface (attributes and methods) as the remote object (in this example, the democlass object created in newdomain ).. Netmask creates a proxy on the client (leleapp.exe in this example) based on the metadata of the remote object. Therefore, the client must contain the metadata of the remote object (simply speaking, it only contains the name and interface definition, but can not contain the actual code implementation ). Because the proxy has the same interface and name as the remote object, the proxy is like a remote object for the client program; the proxy does not actually contain the actual code (such as the method body) that provides services to the client program. Therefore, the proxy only binds itself to an object, then, the customer program sends its own service request to the object. For client programs, remote objects (server objects) are like local objects, while remote objects are like providing services for their local programs.
Note:Some books talk about the concepts of transparent proxy, real proxy, and message sink.
5.2 send value messages and reference messages
Recreate the object, restore the state, and access the object through a proxy. This cross-application domain access method is calledSending data by value)It is somewhat similar to passing parameters by value in C:
Note:In the preceding example, the createinstanceandunwrap () method is called to pass values. This method is only used as an example. Under normal conditions of remoting, sending value passes occurs when the remote object method returns a value to the client, or when the client passes method parameters to the remote object. It will be explained in detail later.
It can be seen from the figure that it is obviously inefficient for large objects to pass the entire object to a local place during value-passing. Therefore, another way is to keep the object remotely (in this example, newdomain), and only create a proxy on the client. As mentioned above, the proxy interface and remote object are identical, therefore, the client thinks that the remote object is still accessed. When the client calls the method on the proxy, the proxy sends the request for the method to the remote object, and the remote object executes the Method Request, finally, return the result. This method is calledTransmit reference messages by reference).
An object or object reference is passed in a encapsulated state (so it is called a mail, which is just a personal guess) during the transfer process ). Therefore, when creating an object, it needs to be unwrapped. Therefore, an andunwrap suffix is added after the createinstanceandunwrap () method. In fact, unwrap also contains a process for creating a proxy.
6. Example of sending and referencing messages
In the above example, we have already used value-passing mails. How can we transmit reference mails? We only need to let the object inherit from the marshalbyrefobject base class, so we can modify democlass, remove the serializable mark, and then let it inherit from marshalbyrefobject:
Public Class Democlass:Marshalbyrefobject{/* Omitted */}
Next, run the program again:
Leleapp.exe
========DomoclassConstructor ======
Newdomain
Jimmy, the countIs1.
Jimmy, the countIs2.
It is found that the obj.showdomain(metadata output is newdomain. it indicates that the values of the democlassmetadata objare not sent to leleapp.exe, but are still stored in newdomain.Some may wonder how I mark serializable and inherit from the marshalbyrefobject program? When we let a type inherit from alalbyrefobject, it will not leave its own application domain, so it will still be carried out by passing reference and sending. Declared as serialable only indicates that it can be serialized.
Before proceeding, let's see what problems can be explained in the above results:The object status is retained.What does this sentence mean? When we call the showcount () method twice, the value of the second run (the value of the count) is based on the result of the first run.
Let's modify Test2 () and create a democlass instance to see what will happen:
Static VoidTest2 (){
AppdomainCurrentdomain = appdomain. currentdomain;
Console. Writeline (currentdomain. friendlyname );
// Create a new application domain-newdomain
AppdomainNewdomain = appdomain. createdomain ("Newdomain");
Democlass OBJ, obj2;
// Create an object in the new application domain
OBJ = (democlass) newdomain. createinstanceandunwrap ("Classlib", "classlib. democlass");
OBJ. showappdomain ();
OBJ. showcount ("Jimmy");
OBJ. showcount ("Jimmy");
// Create another obj2
Obj2 = (democlass) newdomain. createinstanceandunwrap ("Classlib", "classlib. democlass");
Obj2.showappdomain ();
Obj2.showcount ("Zhang");
Obj2.showcount ("Zhang");
}
Run Test2 () to get the following output:
Leleapp.exe
========DomoclassConstructor ======
Newdomain
Jimmy, the countIs1.
Jimmy, the countIs2.
======= Domoclass constructor ======
Newdomain
Zhang, the count is 1.
Zhang, the count is 2.
What did we find this time?For OBJ and obj2, two objects are created in newdomain to serve them respectively, and the two objects are created only once (note that only one constructor is called ).This method is calledClient activated object (CAO ).Let's take a look at the second example provided by the previous article. Can we publish the results here? As for the customer activation object, we will see it later. Here we will first make an impression.
7. Customer application (domain), server assembly, Host application (domain)
What we usually understand when we see remoting is the interaction between the local client and the remote server. In fact, all accesses that span the appdomain belong to remoting. Whether the two AppDomains are in the same process, in different processes, or on different machines. Remoting may consist of two parts: a server and a client ). However, from the appdomain perspective, the server appdomain only provides a runtime environment for remote objects that actually provide services. Therefore, when we mention remoting, we should regard it as three parts. In this way, the concepts will be clearer in future operations and in my subsequent discussions:
- The Host application (domain), the environment where the service program runs (the appdomain where the service object is located), which can be a console application, a Windows form program, a Windows service, or a IIS worker process. In the preceding example, newdomain is used.
- A Service Program (object) is a program (or object) that responds to a customer request. It is generally of a type inherited from externalbyrefobject and is represented as an assembly. In the preceding example, democlass is used.
- The client application (domain) that sends a request to the Host application (or object ). In the preceding example, leleapp.exe is used.
In this article, sometimes I may also use such words as client side and server side. When talking about client side, it only refers to client applications; when it comes to the server, it refers to the Service Program and the Host application.
As we can see, in the above example, the client and the Host application are located in different application domains of the same process, although in most cases they are located in different processes.
In section 3 of this chapter, when the createinstanceandunwrap () method is called to create a democlass object on the instance of the current application domain, this is an extreme situation: that is, the client application domain and the Host application domain are the same application domain consoleapp.exe.
Note:At the bottom of the application domain, there is also a code execution domain called context ). An appdomain can contain multiple environments. Cross-environment access can also be considered as a special case of remoting. However, this article does not cover this part.