我可以做某些组件的默认AppDomain中使用卷影副本?(Can I make the defaul

2019-07-04 14:57发布

为什么我想这样做一个简短的解释:

我忙着写面向Autodesk Revit Architecture软件测试2010插件我的插件代码是繁琐的极端,因为我必须重新启动欧特克为每个调试会话,手动加载Revit项目,单击加载项选项卡上,然后开始我的插件。 这只是时间太长。

我写了承载了IronPython的解释第二插件。 这样一来,我可以玩与Revit中提供的API。 但最终,该代码在C#重写 - 和调试。

很简单,我想:只要加载从IronPython的脚本插件DLL和锻炼吧。 这并不工作,但一旦加载,我不能在Visual Studio重新编译,因为DLL现在被装载在Revits AppDomain中。

很简单,我想(与StackOverflow上的一点帮助):只要加载一个新的AppDomain的DLL。 唉,RevitAPI对象不能被封送到另一个应用程序域,因为它们不延伸MarshalByRefObject

我想我可能会到一些与卷影副本。 ASP.NET似乎是这样。 但是看完MSDN上的文档,似乎创造一个AppDomain的时候,我只能指定。

我可以改变这个当前(默认)的AppDomain? 我可以强制它使用的DLL的卷影副本从一个特定的目录?

Answer 1:

我不知道你正在尝试做的,但也有一些过时的方法来打开影拷贝在当前的AppDomain。

AppDomain.CurrentDomain.SetCachePath(@"C:\Cache");
AppDomain.CurrentDomain.SetShadowCopyPath(AppDomain.CurrentDomain.BaseDirectory);
AppDomain.CurrentDomain.SetShadowCopyFiles();


Answer 2:

有时候这是不可能的,因为,例如,你正在写一个插件修改Main()方法的代码和它是由一个经理实例化。

在这种情况下,我建议你组装和PDB(在AssemblyResolve事件相关的)复制到一个临时位置,并从那里加载它们与Assembly.LoadFile()(未LoadFrom())。

优点: - 无DLL锁定。 - 每一个目标组件重新编译您的时间可以访问新版本(这就是为什么.LoadFile())。 - 整个组件处于AppDomain.CurrentDomain完全可用。

缺点: - 文件复制是必要的。 - 大会的不能被卸载,因为资源没有释放,可能是不方便。

问候,

PD:此代码的工作。

/// <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;
            }
        }
    }
}


Answer 3:

现在有一个的Revit插件动态加载/卸载其他的Revit插件,让你可以改变,重新编译和测试而无需重新打开Revit项目。 我发现它的建筑编码器博客 。 它配备了的Revit SDK。



文章来源: Can I make the default AppDomain use shadow copies of certain assemblies?