Loading and unloading assemblies through the application domain AppDomain

Source: Internet
Author: User

The door of the Microsoft assembly car seemed to open the door to the loading of the cargo but shut off the unloaded workers. There is only one key to the door, and it takes a little thought to get it. When I was learning remoting, I encountered a disturbing problem, that is remoting for remote objects only to provide the Register method, if you want to log off, only a way. Careful developers will find that the reflection mechanism in Visual Studio.NET also faces this problem. You can find all the documentation on MSDN, in the Assembly class, you'll never see the load method, but you won't be able to trace the unload. After we load the assembly, can't we unload it?

Think about a scene like this. You dynamically load a DLL file by reflection, and now you need to delete or overwrite the file without closing the program, what happens? Unfortunately, you are prompted to be unable to access the file. In fact, the file is in the state of being called, when the file is to be modified, there will be contention.

Obviously, it is necessary to provide an uninstall feature for an assembly, but why does Microsoft not provide it in its products? The CLR Product Unit Manager (unit manager) Jason Zander explains why the feature was not implemented in the article why isn ' t there an assembly.unload method . Flier_lu in his blog (assembly.unload) has a detailed introduction to the Chinese language. This article describes a compromise method to resolve an uninstall assembly. Eric Gunnerson also mentions in the article "AppDomain and dynamic Loading" thatassembly.load () usually works fine, but the assembly cannot be unloaded independently (only the AppDomain can unload). Enrico Sabbadin in the article "Unload assemblies from a application Domain" also has relevant vb.net to implement the function of the relevant instructions.

In particular, Flier_lu's blog has a very detailed code. However, these codes are not described in detail. I also need this feature in my project. This piece of code gives me a big hint. But in the actual implementation, still encountered some specific problems. So I still want to talk about my experience.

The idea of implementing an AppDomain to unload an assembly is very clear. Because of the non-special needs in the programming, we are all running in the same application domain. Since the uninstallation of the Assembly has the above flaw, we must close the application domain to unload the assembly that has already been loaded. However, the main program domain cannot be closed, so the only way to do this is to set up a subroutine domain in the main program domain that specifically implements the assembly's loading. Once you uninstall these assemblies, you only need to unload the subroutine domain, which does not affect the execution of the main program domain.

But now it seems that the main problem is not how the subroutine domain is created, but the key is that we have to implement a mechanism to achieve communication between the two program domains. If you are familiar with remoting, you will think that this question is not remoting with the mechanism of a few similarities? Then the answer can be ready, right, is the use of proxy Method! However, unlike remoting, there is a relationship between two program domains. Because the subroutine domain is established in the main program domain, the control of the domain is obviously not the same as remoting. I want to first use a diagram to express the mechanism of implementation:

Description
1. The loader class provides methods for creating sub-program domains and unloading program domains;
2, the RemoteLoader class provides the loading assembly method;
3, the loader class obtains the proxy object of the RemoteLoader class, and calls the method of RemoteLoader class;
4, the method of RemoteLoader class is completed in the sub-program domain;
5, loader class and RemoteLoader class are placed in the AssemblyLoader.dll assembly file;

Let's look at the code again:
Loader class:

Setremoteloaderobject () Method:

PrivateAppDomain domain =NULL; PrivateHashtable domains =NewHashtable (); PrivateRemoteLoader RL =NULL; PublicRemoteLoader Setremoteloaderobject (stringdllName) {AppDomainSetup Setup=NewAppDomainSetup (); Setup. Shadowcopyfiles="true"; Domain= Appdomain.createdomain (DllName,NULL, Setup); Domains.        ADD (Dllname,domain); Try{RL=(assemblyloader.remoteloader) domain. CreateInstanceFromAndUnwrap ("AssemblyLoader.dll","Assemblyloader.remoteloader"); }    Catch    {        Throw NewException (); }}

The variable RL in the code is the RemoteLoader class object, which is its private member in the loader class. The Setremoteloaderobject () method actually provides two functions, one is to create the subroutine domain, and the second is to obtain the RemoteLoader class object.

Please be sure to note the statement:
RL = (assemblyloader.remoteloader) domain. CreateInstanceFromAndUnwrap ("AssemblyLoader.dll", "Assemblyloader.remoteloader");

This statement is the key to achieving communication between two program domains. Because the loader class is in the main program domain, the RemoteLoader class is in the sub-program domain. If we display the instantiated RemoteLoader class object RL in the loader class, the main program domain, the method called RL is actually called in the main program domain. Therefore, we must use the proxy way to obtain the RL object, which is the purpose of the CreateInstanceFromAndUnwrap method. Where parameter one is the assembly file name of the class object to be created, and parameter two is the type name of the class.

The Createcreateinstancefromandunwrap method has multiple overloads. The calling method in the code is one of the overloads when the RemoteLoader class is the default constructor. If the constructor for the RemoteLoader class has parameters, the method should read:

Object [] parms == bindingflags.createinstance | |  = (assemblyloader.remoteloader) domain. CreateInstanceFromAndUnwrap ("AssemblyLoader.dll","  Assemblyloader.remoteloader",true, bindings,null, parms,null ,null,null);

You can refer to MSDN for detailed invocation methods.

The Unload method and LoadAssembly method () for the following loader classes:

 Public Assembly loadassembly (string  dllName) {    try    {        setremoteloaderobject ( DllName);         return RL. LoadAssembly (DllName);    }     Catch (Exception)    {        thrownew  assemblyloadfailureexception ();    }}

 Public void Unload (string  dllName) {    if  (domains. ContainsKey (dllName))    {        = (AppDomain) domains[dllname];        AppDomain.Unload (appDomain);        Domains. Remove (DllName);    }            }

When we call the Unload method, the assembly that the domain domain loads will be unloaded as well. The exception assemblyloadfailureexception in the LoadAssembly method is a custom exception:

 public  class   Assemblyloadfailureexception:exception { pub Lic  assemblyloadfailureexception (): base   () {}  public " Span style= "color: #0000ff;" >override  string   Message {get   { return   assembly Load Failure  Span style= "color: #800000;"            > " ; }        }    }

Since the RemoteLoader class instance obtained in the loader class must be proxied, the class object must support serialization. So we can make this class derive MarshalByRefObject. Code for the RemoteLoader class:

 Public classRemoteloader:marshalbyrefobject { PublicRemoteLoader (stringdllName) {            if(Assembly = =NULL) {Assembly=Assembly.LoadFrom (dllName); }        }                PrivateAssembly Assembly =NULL;  PublicAssembly loadassembly (stringdllName) {            Try{Assembly=Assembly.LoadFrom (dllName); returnAssembly; }            Catch(Exception) {Throw Newassemblyloadfailureexception (); }        }    }

With the two classes above, we can implement assembly loading and unloading. In addition, to ensure that objects in the application domain are purged in memory, the two classes should implement the IDisposable interface and implement the Dispose () method.

However, in the actual operation process, I found in the RemoteLoader class of loadassembly method, is the existence of legacy. In my loadassembly method, a assembly object is returned. What makes me baffled is that, although they are all assembly objects, when some assemblies are loaded and return assembly, serializationexception exceptions are thrown in the loader class and the deserialized object state is reported to be insufficient. This exception occurs during serialization deserialization. I have repeatedly compared two assemblies, one that can be loaded and serialized normally, and one that throws up an exception. The assembly that throws the exception is nothing special, and I have not repeatedly loaded the assembly elsewhere in the program. This is a question!!

But usually in the RemoteLoader class, the method to be implemented does not return an assembly object, but instead creates an object for that assembly after the assembly is loaded through reflection. Because class objects are of type object, there is no problem with serialization at this time. In my project, because I want to get the version number of the assembly and compare the version number to determine if it needs to be updated, in the RemoteLoader class, I only need to return the version number string type of the assembly after the assembly is loaded. String types are absolutely serializable-supported.

AssemlbyLoader.Dll source code can be obtained by clicking here. In the application, a reference to the assembly is displayed, and then the loader class object is instantiated to invoke the method. I also made a simple test procedure, using the LoadAssembly method. You can test if, as I say, for some assemblies, a serialized exception might be thrown!?

Test the code click here to get the test interface as follows:

At the same time, you can also test, direct loading and through the AppDomain loading, delete the assembly file, what is the difference?

Original link:

Loading and unloading assemblies through the application domain AppDomain

Loading and unloading assemblies through the application domain AppDomain

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.