代码之家  ›  专栏  ›  技术社区  ›  Daren Thomas

可以让默认的AppDe域使用某些程序集的影子副本吗?

  •  9
  • Daren Thomas  · 技术社区  · 15 年前

    关于我为什么要这么做的简短解释:

    我正忙着为autodesk revit architecture 2010编写插件。测试我的插件代码非常麻烦,因为我必须为每个调试会话重新启动autodesk,手动加载一个revit项目,单击“加载项”选项卡,然后启动我的插件。只是时间太长了。

    我已经编写了第二个插件,托管一个ironpython解释器。这样,我就可以玩RVIT提供的API了。但最终,代码必须用c重写并调试。

    很简单,我想:只需从ironpython脚本中加载插件dll并练习它。这确实有效,但是一旦加载,我就不能在visual studio中重新编译,因为dll现在加载在revits appdomain中。

    很简单,我想(在stackoverflow的帮助下):只需在一个新的appdomain中加载dll。唉,revitapi对象不能被封送到另一个appdomain,因为它们没有扩展 MarshalByRefObject .

    我想我可能是在用影子复制的东西。asp.net似乎正在这样做。但是阅读MSDN上的文档,我似乎只能指定 创建 应用程序域。

    我可以将这个更改为当前(默认)AppDealm吗?我能强制它使用来自特定目录的DLL的影子拷贝吗?

    3 回复  |  直到 12 年前
        1
  •  5
  •   lubos hasko    15 年前

    我不知道你想做什么,但是有一些不推荐的方法可以在当前的appdomain上打开shadowcopy。

    AppDomain.CurrentDomain.SetCachePath(@"C:\Cache");
    AppDomain.CurrentDomain.SetShadowCopyPath(AppDomain.CurrentDomain.BaseDirectory);
    AppDomain.CurrentDomain.SetShadowCopyFiles();
    
        2
  •  2
  •   Eu_UY    14 年前

    有时不可能修改main()方法代码,因为,例如,您正在编写一个插件,它由一个管理器实例化。

    在这种情况下,我建议您将程序集和pdb(以及assemblyResolve事件中的从属程序集)复制到临时位置,并使用assembly.loadFile()从那里加载它们(而不是loadFrom())。

    赞成的意见: -没有dll锁定。 -每次重新编译目标程序集时,都可以访问新版本(这就是.loadfile()的原因)。 -整个程序集在appdomain.currentdomain中完全可用。

    欺骗: -文件复制是必要的。 -汇编不能卸载,这可能是不方便的,因为资源是免费的。

    当做,

    警察:这个密码起作用。

    /// <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;
                }
            }
        }
    }
    
        3
  •  1
  •   skeletank    12 年前

    现在有一个用于动态加载/卸载其他插件的插件,这样您就可以在不必重新打开项目的情况下进行更改、重新编译和测试。我在 Building Coder blog . 它附带了revit sdk。