none
Replacing assembly whithout stop application. RRS feed

  • Question

  • Hello, everyone! Is it possible or not?

    That's my test library code.

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace TestDomainLibrary
    {
        [Serializable]
        public class Test : MarshalByRefObject
        {
            public string Foo()
            {
                return "Foo3";
            }
        }
    }
    

     

    And that's my test application code.

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Threading;
    
    namespace Proj_065
    {
        class Program
        {
            static void Main(string[] args)
            {
                test();
                Console.ReadKey();
                test();
                Console.ReadKey();
            }
    
    
            static void test()
            {
                AppDomain domain = null;
                try
                {
                    string callingDomainName = Thread.GetDomain().FriendlyName;
                    AppDomainSetup ads = new AppDomainSetup ();
                    ads.ApplicationBase = System.Environment.CurrentDirectory; ads.DisallowBindingRedirects = false;
                    ads.DisallowCodeDownload = true;
                    ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
                    domain = AppDomain.CreateDomain("AD #2", null, ads);               
    
                    // A proxy to the object is returned.
                    dynamic mbrt = domain.CreateInstanceAndUnwrap("TestDomainLibrary", "TestDomainLibrary.Test");
                    string param = mbrt.Foo();
                  
                    Console.WriteLine(param);
                }
                finally
                {
                    AppDomain.Unload(domain);
                }           
            }
        }
    }
    
    
    

    If i don't invoke the "Foo" method then i can replace this assembly library while my test application is running. Otherwise i can't do it. What do i wrong? Thanks.

     

    Friday, October 21, 2011 12:02 PM

Answers

  • Hi Booster1,

    Unlike the Win32 loader, the CLR loader does not resolve and automatically load the subordinate assemblies. Rather, the subordinate assemblies are loaded on demand only if they are actually needed. In the CLR, loading typically is triggered by the JIT compiler based on types. When the JIT compiler tries to convert a method body from CIL to machine code, it needs access to the type definition of the declaring type as well as the type definitions for the type's fields.

    For first scenario, you call 'domain.CreateInstanceAndUnwrap()', 'string param = mbrt.Foo() '  and then ''AppDomain.Unload(domain)'.

    TestDomainLibrary.dll is not loaded into memory until first method call 'mbrt.Foo()' hit.

    After newly created domain unloaded via the call 'AppDomain.Unload(domain)', all the assemblies in this domain (other than domain-neutral assemblies) will be removed as well.

    However, since the type of 'domain' object is referenced by main assembly, TestDomainLibrary.dll still resides in memory. It can be observed via Process Explorer. So you cannot replace it while your application is running.

    To get it around, please visit http://blogs.msdn.com/b/suzcook/archive/2003/07/08/unloading-an-assembly.aspx for more helps.

    For another scenario, you call 'domain.CreateInstanceAndUnwrap()' and then ''AppDomain.Unload(domain)'. It means that TestDomainLibrary.dll is actually not loaded into memory according to assembly loading policy implemented by CLR Loader. It can be observed via Process Explorer as well. So you can freely replace TestDomainLibrary.dll with any other file while your application is running. 

     

    Sincerely,
    Robin
    If it solved your problem,Please click "Mark As Answer" on that post and "Mark as Helpful". Lucky everyday!


    • Edited by Lucky Robin Tuesday, October 25, 2011 7:58 AM
    • Marked as answer by Booster1 Thursday, October 27, 2011 9:19 AM
    Tuesday, October 25, 2011 6:30 AM
  • There's a workaround that may or may not circumvernt the problem for you.

    On NTFS, you can't delete a dll while it is loaded, or an exe while it is running, of course.  You can, however, rename it.

    What I often do to "upgrade" an app in place without stopping it is to rename the old version, and copy the new version in. The running app will keep using the old version (if it was loaded). The next time the app starts it is guaranteed to use the new version.

     

    • Marked as answer by Booster1 Thursday, October 27, 2011 9:19 AM
    Tuesday, October 25, 2011 10:02 AM

All replies

  • Hi Booster1,

    Unlike the Win32 loader, the CLR loader does not resolve and automatically load the subordinate assemblies. Rather, the subordinate assemblies are loaded on demand only if they are actually needed. In the CLR, loading typically is triggered by the JIT compiler based on types. When the JIT compiler tries to convert a method body from CIL to machine code, it needs access to the type definition of the declaring type as well as the type definitions for the type's fields.

    For first scenario, you call 'domain.CreateInstanceAndUnwrap()', 'string param = mbrt.Foo() '  and then ''AppDomain.Unload(domain)'.

    TestDomainLibrary.dll is not loaded into memory until first method call 'mbrt.Foo()' hit.

    After newly created domain unloaded via the call 'AppDomain.Unload(domain)', all the assemblies in this domain (other than domain-neutral assemblies) will be removed as well.

    However, since the type of 'domain' object is referenced by main assembly, TestDomainLibrary.dll still resides in memory. It can be observed via Process Explorer. So you cannot replace it while your application is running.

    To get it around, please visit http://blogs.msdn.com/b/suzcook/archive/2003/07/08/unloading-an-assembly.aspx for more helps.

    For another scenario, you call 'domain.CreateInstanceAndUnwrap()' and then ''AppDomain.Unload(domain)'. It means that TestDomainLibrary.dll is actually not loaded into memory according to assembly loading policy implemented by CLR Loader. It can be observed via Process Explorer as well. So you can freely replace TestDomainLibrary.dll with any other file while your application is running. 

     

    Sincerely,
    Robin
    If it solved your problem,Please click "Mark As Answer" on that post and "Mark as Helpful". Lucky everyday!


    • Edited by Lucky Robin Tuesday, October 25, 2011 7:58 AM
    • Marked as answer by Booster1 Thursday, October 27, 2011 9:19 AM
    Tuesday, October 25, 2011 6:30 AM
  • There's a workaround that may or may not circumvernt the problem for you.

    On NTFS, you can't delete a dll while it is loaded, or an exe while it is running, of course.  You can, however, rename it.

    What I often do to "upgrade" an app in place without stopping it is to rename the old version, and copy the new version in. The running app will keep using the old version (if it was loaded). The next time the app starts it is guaranteed to use the new version.

     

    • Marked as answer by Booster1 Thursday, October 27, 2011 9:19 AM
    Tuesday, October 25, 2011 10:02 AM
  • Thanks. Probably i need to use new AppDomain for entire application so that i can free assembly. By the way i have another question about freeing assembly. I've read that we can use method ShadowCopyFile of AppDomain. But it's very embarrassing to me because i can only replace assembly in the cache, not original .dll. It's very inconvenient because i must work with folder structure of cache.
    Wednesday, October 26, 2011 1:19 PM
  • Thanks everyone, i understand all of it now.
    Thursday, October 27, 2011 9:19 AM