我想要这样做的简短说明:
我正在为Autodesk Revit Architecture 2010编写插件。测试我的插件代码非常麻烦,因为我必须为每个调试会话重新启动Autodesk,手动加载Revit项目,单击Add-Ins选项卡然后启动我的插件。这只是花了太长时间。
我写了第二个插件来托管IronPython解释器。通过这种方式,我可以使用Revit提供的API。但最终,代码必须在C#中重写 - 并进行调试。
很简单,我想:只需从IronPython脚本加载插件DLL并进行练习即可。这确实有效,但一旦加载,我无法在Visual Studio中重新编译,因为DLL现在已加载到Revits AppDomain中。
很简单,我想(在StackOverflow的帮助下):只需在新的AppDomain中加载DLL即可。唉,RevitAPI对象无法封送到另一个AppDomain,因为它们不会扩展MarshalByRefObject
。
我想我可能会使用影子副本。 ASP.NET似乎正在这样做。但是阅读MSDN上的文档,我似乎只能在创建 AppDomain时指定它。
我可以为当前(默认)AppDomain更改此设置吗?我可以强制它使用来自特定目录的DLL的卷影副本吗?
答案 0 :(得分:5)
我不知道你要做什么,但有一些不赞成使用的方法可以在当前的AppDomain上打开ShadowCopy。
AppDomain.CurrentDomain.SetCachePath(@"C:\Cache");
AppDomain.CurrentDomain.SetShadowCopyPath(AppDomain.CurrentDomain.BaseDirectory);
AppDomain.CurrentDomain.SetShadowCopyFiles();
答案 1 :(得分: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;
}
}
}
}
答案 2 :(得分:1)
现在有一个Revit插件可以动态加载/卸载其他Revit插件,这样您就可以更改,重新编译和测试,而无需重新打开Revit项目。我在Building Coder blog找到了它。它随附Revit SDK。