Hot update for ". NET deep Breathing" assemblies

Source: Internet
Author: User

When an assembly is loaded and used for data integrity and security considerations, the assembly file (in 99.9998% In the case of a. dll file) will be locked, if you want to update the assembly (actually replace the DLL file), is not operational, then you have to exit the application, replace the file and then start the program.

In most cases this is possible, but sometimes, such as ASP. NET or some service processes that need to be running all the time, restarting the program is not as good.

If you want to hot-update the assembly, that is, to replace the file while the program is running, there is a very familiar scenario-image copy, if you are not familiar with. NET, you certainly have not heard of. Of course, the term is also very harsh, no way, had to translate, the original word is Shadow Copy, Shadow is Shadow, shadow, the meaning of the image, that also had to so translated. However, you do not have to worry about it is very abstract very high-end, in fact, as long as the hard to learn, nothing is offensive.

I use a word to summarize the shadow copy (also can be called copy, but I do not like to copy the word, very yellow very violent feeling)--the application domain when loading the assembly, the assembly file will be copied to another place, and then loaded. In this way, when the assembly file is used, it locks the copied file, that is, the original file we can safely replace, wait for the right time, the application restarted, run again, will automatically copy the latest assembly into the cache directory, and then execute the latest version of the code. It's a good idea to put these calls into a new application domain because the benefit is that you don't have to restart the application, and as long as you unload an application domain and recreate a new one, the latest assembly is automatically loaded. And, usually you should do it, create an application domain, execute the code inside, and unload the application domain when it's done, saving resources.

When the application is running, the default is to create an application domain, in short, there will be at least one application domain in a process, if you put a piece of code in a new application domain to execute, and you want to finish, you can pass the results back to the main application domain, then the old weeks ago written methods, Remember the old week before, want to pass the object by reference, derive from the MarshalByRefObject class, want the object to be passed by value, let it support serialization.

When creating a new application domain, you can pass a Setupinfo object that has a Shadowcopyfiles property, although the type it defines is string, but you must not understand the error, do not assign a file path to it. Old weeks ago saw a friend understand wrong, it mistakenly thought that this property is used to set the Copy assembly file cache path, the result code is always not good to write. Alas, this is what happens when you don't look at MSDN.

Don't mess up, set the cache directory for the replication assembly is the CachePath property, not the Shadowcopyfiles property. The Shadowcopyfiles property can only use a value of two strings, set to True if you want to enable image replication, or set False if you want to disable or simply leave the default null value. It is also said that it is a bool value represented by a string.

Below, we use an example to perform a bit, very wonderful.

First, you get a class library project, and then you write the simplest class in the whole universe.

namespace testlib{    publicclass  Demo    {        publicstring   Call ()        {            return"Ver-3";}}    }

and the main startup project is a console application, here, the old weeks want to set up a new application domain Privatebinpath, this property can be set up a bunch of directories, can be a relative path, in fact, it should be a relative path, because this directory can not be set, it must be a subdirectory of the application directory. If it is a multiple directory, it can be separated by a semicolon (;) in English.

The ApplicationBase path specifies the application, which is the directory that the. exe launches, regardless of whether you create multiple new application domains, this directory must be specified as the current EXE's startup directory . Otherwise you try, you can't run, because the application domain is isolated, so in the newly created application domain you must also load the assembly where the current EXE resides, which is necessary because it is the main entry point.

The path specified by the Privatebinpath property must be a subdirectory of the application directory, for example, our project in debug mode, usually the EXE generated into the bin \ Debug directory, so you can create a subdirectory in the debug directory, I created a, Called Extdlls, then I will put the DLL file to be used in this directory, and set privatebinpath = "Extdlls", so that, even if the project does not reference this class library project, in the run phase it will automatically go to this Extdlls directory to find, found the load , if not found will be "hehe".

My class library project named TestLib, in order to allow it to automatically copy the latest version into the Extdlls directory, you can open the Project Properties window of the Class library project, switch to the Build Events page, and enter the following command in post-build command line:

" $ (TargetPath) " " $ (SolutionDir) myapp\bin\debug\extdlls\ "

So, every time I rebuild a class library project, I automatically copy the DLL file.

Well, the following focus is on the main project, where you can create a new application domain and then call the code in the class library.

AppDomainSetup Setup =NewAppDomainSetup (); Setup. ApplicationBase=AppDomain.CurrentDomain.SetupInformation.ApplicationBase; Setup. ApplicationName="Extfuncs"; Setup. Privatebinpath="Extdlls"; Setup. Shadowcopyfiles="true"; AppDomain Newdom= Appdomain.createdomain ("Hello",NULL, Setup); Newdom.docallback (()={Type T= Type.GetType ("Testlib.demo, TestLib"); //get public parameterless constructorsConstructorInfo costr = T.getconstructor (Newtype[] {}); //call the constructor to create the type instance                    ObjectInstance = CoSTR. Invoke (New Object[] { }); //find the method to invokeMethodInfo m = T.getmethod ("Pager", BindingFlags.Public |bindingflags.instance); //call method, get return value                    Objectretval = M.invoke (instance,New Object[] { }); Console.WriteLine ($"Call output: {retval}"); Console.WriteLine ("\n==================================="); //the path of the output reference assembly                    varRefasses =AppDomain.CurrentDomain.GetAssemblies (); foreach(varTheinchrefasses) {Console.WriteLine ("Name:"+The . GetName ().                        Name); Console.WriteLine ("Path:"+The .                        Location);                    Console.WriteLine ();                }                }); AppDomain.Unload (Newdom); //uninstalling an application domain

The experiment shows that the value of the ApplicationName property can be arbitrarily written, but the ApplicationBase property must be the directory in which the current application resides.

Here I use the reflection method to invoke, the DoCallback method allows code execution in another application domain, and the code content is associated with a delegate.

After reflection calls the test class library, I also use this code to output the paths of all the assemblies referenced by the new application domain.

                    var refasses = AppDomain.CurrentDomain.GetAssemblies ();                     foreach (var in refasses)                    {                        Console.WriteLine (" name:" + "The") . GetName (). Name);                        Console.WriteLine (" path:" + The  . Location);                        Console.WriteLine ();                    }

Because this code is executed in a new application domain, the CurrentDomain property refers to the newly created application domain, not the default domain that is created when the process runs.

The reason to output a path after reflection is because the application domain is loaded dynamically, that is, when you use a type in a class library, and if you do not access anything in the class library, the assembly is not loaded.

Why do I have to output the path, which is to make it clear to everyone that the TestLib class library has been copied to another directory for execution. Please see:

As you can see from this diagram, the default cache assembly path is under AppData \ Local \ assembly under your user configuration directory.

Perhaps you think this default cache path is not good, can you customize AH? Yes, the old week before. CachePath property, for which you assign a path to this property, the cached assembly is placed in the custom path. For example, I create a new Tempass directory under the Debug directory to hold the temporary copy of the Assembly.

Setup. CachePath = Cache_path;

And then you look at its path.

See, is it a change?

Now, let's verify that it's not hot to update.

Run EXE first, output Ver-1,.

OK, keep EXE running, do not close, and then modify the code of the Class Library project.

     Public class Demo    {        publicstring call ()        {            return"Ver-2 ";        }    }

Change 1 to 2.

Regenerate the class library project, which is automatically copied to the Extdlls directory.

Now, by pressing any key other than ESC in the console window, the application domain is re-built and the execution class library code is loaded because I have a loop that exits only if the ESC key is encountered.

At this point, you see that the output has changed.

Instead of exiting the application, you can replace the assembly file, which is especially true for service applications.

In order to write code with intelligent hints, if I do not want to use reflection, but directly in the VS Reference Class Library project, try, after the reference, the Testlib property of "Copy Local" to False, because the Extdlls directory already has files, do not have to copy, in the new application domain when executing , it is automatically searched.

Then change the code in the DoCallback method:

                Newdom.docallback (() =                {                    new  Testlib.demo ();                    Console.WriteLine ($" output: {DM. Call ()}");                

Now the code is a lot easier, right, just two lines will be finished.

Can it be run, of course. See.

What's up, smelling?

Well, the old week of celery fried fish eggs cooked, hungry, dinner.

Sample source code Download

Hot update for. NET deep breathing assemblies

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.