Can I make the default AppDomain use shadow copies of certain assemblies?

后端 未结 3 1088
生来不讨喜
生来不讨喜 2020-12-15 00:49

A short explanation of why I want to do this:

I am busy writing a plugin for Autodesk Revit Architecture 2010. Testing my plugin code is extremly cumbersome, as I ha

相关标签:
3条回答
  • 2020-12-15 01:01

    I don't know what you are trying to do but there are some deprecated methods to turn on ShadowCopy on the current AppDomain.

    AppDomain.CurrentDomain.SetCachePath(@"C:\Cache");
    AppDomain.CurrentDomain.SetShadowCopyPath(AppDomain.CurrentDomain.BaseDirectory);
    AppDomain.CurrentDomain.SetShadowCopyFiles();
    
    0 讨论(0)
  • 2020-12-15 01:13

    Sometimes it's not possible to modify the Main() method code because, for example, you're writing a plug-in and it's instantiated by a manager.

    In that case i suggest you copy the assembly and pdb (and dependent ones in AssemblyResolve event) to a temp location and load them from there with Assembly.LoadFile() (not LoadFrom()).

    Pros: - no dll locking. - every time the target assembly is recompiled you get access to the new version (that's why .LoadFile()). - the whole assembly is fully available in AppDomain.CurrentDomain.

    Cons: - file copying is necessary. - assemblys can't be unloaded and that could be inconvenient because resources are no freed.

    Regards,

    PD: This code does the work.

    /// <summary>
    /// Loads an assembly without locking the file
    /// Note: the assemblys are loaded in current domain, so they are not unloaded by this class
    /// </summary>
    public class AssemblyLoader : IDisposable
    {
        private string _assemblyLocation;
        private string _workingDirectory;
        private bool _resolveEventAssigned = false;
    
        /// <summary>
        /// Creates a copy in a new temp directory and loads the copied assembly and pdb (if existent) and the same for referenced ones. 
        /// Does not lock the given assembly nor pdb and always returns new assembly if recopiled.
        /// Note: uses Assembly.LoadFile()
        /// </summary>
        /// <param name="assemblyOriginalPath"></param>
        /// <returns></returns>
        public Assembly LoadFileCopy(string assemblyLocation)
        {
            lock (this)
            {
                _assemblyLocation = assemblyLocation;
    
                if (!_resolveEventAssigned)
                {
                    _resolveEventAssigned = true;
    
                    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyFileCopyResolveEvent);
                }
    
                //  Create new temp directory
                _workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(_workingDirectory);
    
                //  Generate copy
                string assemblyCopyPath = Path.Combine(_workingDirectory, Path.GetFileName(_assemblyLocation));
                System.IO.File.Copy(_assemblyLocation, assemblyCopyPath, true);
    
                //  Generate copy of referenced assembly debug info (if existent)
                string assemblyPdbPath = _assemblyLocation.Replace(".dll", ".pdb");
                if (File.Exists(assemblyPdbPath))
                {
                    string assemblyPdbCopyPath = Path.Combine(_workingDirectory, Path.GetFileName(assemblyPdbPath));
                    System.IO.File.Copy(assemblyPdbPath, assemblyPdbCopyPath, true);
                }
    
                //  Use LoadFile and not LoadFrom. LoadFile allows to load multiple copies of the same assembly
                return Assembly.LoadFile(assemblyCopyPath);
            }
        }
    
        /// <summary>
        /// Creates a new copy of the assembly to resolve and loads it
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private Assembly AssemblyFileCopyResolveEvent(object sender, ResolveEventArgs args)
        {
            string referencedAssemblyFileNameWithoutExtension = System.IO.Path.GetFileName(args.Name.Split(',')[0]);
    
            //  Generate copy of referenced assembly
            string referencedAssemblyPath = Path.Combine(Path.GetDirectoryName(_assemblyLocation), referencedAssemblyFileNameWithoutExtension + ".dll");
            string referencedAssemblyCopyPath = Path.Combine(Path.GetDirectoryName(args.RequestingAssembly.Location), referencedAssemblyFileNameWithoutExtension + ".dll");
            System.IO.File.Copy(referencedAssemblyPath, referencedAssemblyCopyPath, true);
    
            //  Generate copy of referenced assembly debug info (if existent)
            string referencedAssemblyPdbPath = Path.Combine(Path.GetDirectoryName(_assemblyLocation), referencedAssemblyFileNameWithoutExtension + ".pdb");
            if (File.Exists(referencedAssemblyPdbPath))
            {
                string referencedAssemblyPdbCopyPath = Path.Combine(Path.GetDirectoryName(args.RequestingAssembly.Location), referencedAssemblyFileNameWithoutExtension + ".pdb");
                System.IO.File.Copy(referencedAssemblyPath, referencedAssemblyCopyPath, true);
            }
    
            //  Use LoadFile and not LoadFrom. LoadFile allows to load multiple copies of the same assembly
            return Assembly.LoadFile(referencedAssemblyCopyPath);
        }
    
    
        public void Dispose()
        {
            Dispose(true);
        }
    
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_resolveEventAssigned)
                {
                    AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(AssemblyFileCopyResolveEvent);
    
                    _resolveEventAssigned = false;
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-15 01:17

    There is now a Revit plugin for dynamically loading/unloading other Revit plugins so that you can change, recompile, and test without having to reopen the Revit Project. I found it on the Building Coder blog. It comes with the Revit SDK.

    0 讨论(0)
提交回复
热议问题