Load and uninstall an assembly through the appdomain of the application domain [zz]

Source: Internet
Author: User

The door of Microsoft's car assembly seems to only open the door for cargo loading, but it will shut out the unload workers. There is only one key for the door. You have to worry about it. When I was learning remoting, I encountered a disturbing problem, that is, remoting only provides the Register Method for remote objects. If you want to log out, there is only a new way. Careful developers will find that reflection mechanisms in Visual Studio. NET are also facing this problem. You can search all msdn documents. In the Assembly class, you can only see the load method, but cannot find the trace of unload. Can't we unmount the Assembly after it is loaded?

Think about this scenario. You have dynamically loaded a DLL file through reflection. Now you need to delete or overwrite the file without closing the program. What will happen? Sorry, the system will prompt you that you cannot access the file. In fact, the file is in the called State. If you want to modify the file, there will be a race.

Obviously, it is necessary to provide the uninstall function for the Assembly, but why does Microsoft not provide this function in its products? CLR product unit manager Jason Zander in the article why isn't there an assembly. Unload method? Is not implemented. In his blog, flier_lu (Assembly. Unload. This article introduces a compromise solution for uninstalling an assembly. Eric Gunnerson also mentioned in his article appdomain and dynamic loading:Assembly. Load ()It usually runs well, but the Assembly cannot be detached independently (only appdomain can be uninstalled ).Enrico sabbadinIn the article "Unload assemblies from an application domain", there are also instructions on how to implement this function in VB. NET.

In particular, the flier_lu blog has detailed code. However, these codes are not described in detail. I also need this feature in my project. This Code gives me a lot of tips. However, some specific problems still occur in actual implementation. So I still want to talk about my experience.

The idea of using appdomain to uninstall an assembly is very clear. Because of the non-special needs in programming, we all run in the same application domain. Due to the preceding defects in the Assembly uninstallation, we must close the application domain to uninstall the loaded assembly. However, the main program domain cannot be closed, so the only way is to create a subprogram domain in the main program domain to specifically implement assembly loading. Once you need to uninstall these assembly, you only need to uninstall the subroutine domain, it does not affect the execution of the main program domain.

But now it seems that the main problem is not how to create a subroutine domain. The key is that we must implement a mechanism to implement the communication function between two program domains. If you are familiar with remoting, do you think this is not similar to the remoting mechanism? Then the answer is ready. By the way, the proxy is used! However, what is different from remoting is the relationship between two program domains. Because the subprogram domain is created in the main program domain, the control over this domain is obviously different from remoting.

I want to first describe the implementation mechanism using a pair of diagrams:

Note:
1. The loader class provides methods for creating subprogram domains and detaching program domains;
2. The remoteloader class provides the Assembly Loading Method;
3. The loader class obtains the proxy object of the remoteloader class and calls the method of the remoteloader class;
4. The remoteloader class method is completed in the subroutine domain;
5. The loader class and remoteloader class are both stored in the assemblyloader. dll Assembly file;

Let's take a look at the Code:
Loader class:

Setremoteloaderobject () method:

Private appdomain domain = NULL;
Private hashtable domains = new hashtable ();
Private remoteloader RL = NULL; Public remoteloader setremoteloaderobject (string dllname)
{
Appdomainsetup setup = new appdomainsetup ();
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 new exception ();
}
}

The RL variable in the Code is a remoteloader class object, which is a private member of the loader class. The setremoteloaderobject () method provides two functions: creating a subprogram domain and obtaining a remoteloader class object.

Note the following statements:
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 subprogram domain. If we display the instantiated remoteloader Class Object RL In the loader class, that is, the method for calling RL is actually called in the main program domain. Therefore, we must use the proxy method to obtain the RL object, which is the purpose of the createinstancefromandunwrap method. The parameter is the Assembly File Name of the class object to be created, and the parameter is the type name of the class.

The createcreateinstancefromandunwrap method has multiple reloads. The call method in the Code is one of the reloads when the remoteloader class is the default constructor. If the remoteloader class constructor has parameters, the method should be changed:

Object [] parms = {dllname };
Bindingflags bindings = bindingflags. createinstance |
Bindingflags. instance | bindingflags. Public;
RL = (assemblyloader. remoteloader) domain. createinstancefromandunwrap ("assemblyloader. dll", "assemblyloader. remoteloader", true, bindings,
Null, parms, null );

For detailed call methods, refer to msdn.

The following loader class's unload method and loadassembly method ():

Public Assembly loadassembly (string dllname)
{
Try
{
Setremoteloaderobject (dllname );
Return RL. loadassembly (dllname );
}
Catch (exception)
{
Throw new assemblyloadfailureexception ();
}
} Public void unload (string dllname)
{
If (domains. containskey (dllname ))
{
Appdomain = (appdomain) domains [dllname];
Appdomain. Unload (appdomain );
Domains. Remove (dllname );
}
}

When we call the unload method, the Assembly loaded by the program domain will also be uninstalled. Assemblyloadfailureexception in the loadassembly method is a custom exception:

Public class assemblyloadfailureexception: exception
{
Public assemblyloadfailureexception (): Base ()
{
}

Public override string message
{
Get
{
Return "assembly load failure ";
}
}

}

Since the remoteloader class instance obtained in the loader class must be in the form of a proxy, the object of this class must support serialization. Therefore, we can make this class derive marshalbyrefobject. Code of the remoteloader class:

Public class remoteloader: externalbyrefobject
{
Public remoteloader (string dllname)
{
If (Assembly = NULL)
{
Assembly = assembly. loadfrom (dllname );
}
}

Private Assembly = NULL;

Public Assembly loadassembly (string dllname)
{
Try
{
Assembly = assembly. loadfrom (dllname );
Return assembly;
}
Catch (exception)
{
Throw new assemblyloadfailureexception ();
}
}
}

Through the two classes above, we can load and unload the assembly. In addition, to ensure that the objects in the application domain are cleared in the memory, both classes should implement the idisposable interface and implement the dispose () method.

However, in the actual operation process, I found that the loadassembly METHOD OF THE remoteloader class is suffering. In my loadassembly method, an assembly object is returned. What I cannot explain is that, although they are all Assembly objects, when loading some assembly and returning assembly, a serializationexception will be thrown in the loader class, and report the status of the deserialization object is insufficient. This exception occurs during deserialization. I have repeatedly compared two sets. One can be loaded and serialized normally, and the other will throw the above exception. There is nothing special about the Assembly that throws exceptions, and I have not repeatedly loaded the Assembly elsewhere in the program. This is a question !!

However, in the remoteloader class, the method to be implemented does not return an assembly object. Instead, the Assembly object is created after the Assembly is loaded through reflection. Because all class objects are of the object type, serialization will not cause problems. In my project, to obtain the assembly version number, compare the version number to determine whether to update it. Therefore, in the remoteloader class, after loading the assembly, returns the version number string type of the Assembly. The string type absolutely supports serialization.

You can click here to obtain the source code of assemlbyloader. dll. In the application, add a reference to the Assembly and instantiate the loader class object to call this method. I also made a simple test program using the loadassembly method. You can test whether, as I said, serialization exceptions may be thrown for some assemblies !?

Click here to obtain the test code. The test interface is as follows:

At the same time, you can also test what is the difference between directly loading and loading through appdomain to delete assembly files?

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.