这有点复杂,但我会尽量使其尽可能清晰。我创建了一个Visual Studio扩展,当您右键单击某个项目(并且该项目符合某些条件)时,该菜单项会添加到上下文菜单中。菜单应该触发过程将:在Visual Studio扩展中创建域和加载程序集
1)建设项目
2)创建一个新的AppDomain
3)装载新组装成新的AppDomain
4)从第三个程序集中定义的新AppDomain中返回一些对象(即不是扩展程序集或构建的项目),但参考其他两个。
我不断遇到的问题是使用数字4,并且说服扩展名从第三个程序集(我们称之为foo.dll
和FooAssembly
)的类型是相同的类型。
在我的分机(我们称之为extension.dll
)我有这样的:
// assemblyPath is the path to the dll I just build for the selected project
var setup = new AppDomainSetup()
{
ApplicationBase = System.IO.Path.GetDirectoryName(assemblyPath)
};
domain = AppDomain.CreateDomain("Test_AppDomain", AppDomain.CurrentDomain.Evidence, setup);
// FooAssembly is defined in foo.dll and is reference by *both* the project.dll and
// but the extension.dll it exists both in the assemblyPath folder
// and typeof(FooAssembly).Assembly.Location which is NOT the same as
// the current AppDomain's CodeBase because the current CodeBase is the
// CodeBase of Visual Studio in this context
var obj = domain.CreateInstanceAndUnwrap(
typeof(FooAssembly).Assembly.FullName,
typeof(FooAssembly).FullName,
false,
BindingFlags.Default,
null,
new object[] { assemblyPath, typeof(FooAssembly).Assembly.Location }, null, null);
// This says the type is MarshalByRefObject
System.Diagnostics.Debug.WriteLine(obj.GetType().Name);
// this sets collection to null because it can't cast it
// which is essentially my problem
collection = obj as FooAssembly;
现在我FooAssembly
,在foo.dll
定义和引用双方extension.dll
和project.dll
看起来是这样的:
public class FooAssembly: MarshalByRefObject
{
private Assembly _assembly;
public FooAssembly(string assemblyPath, string parentPath)
{
AppDomain.CurrentDomain.AssemblyResolve += (o, e) =>
{
// this event never seems to get fired
System.Diagnostics.Debug.WriteLine($"attempt to resolve {e.Name} for {e.RequestingAssembly.FullName}");
return null;
};
// this didn't seem to help
//Assembly.LoadFrom(parentPath); // load spider assembly from same place (hopefully)...
// I've tried LoadFrom as well, with the same result
_assembly = Assembly.LoadFile(assemblyPath);
}
public override object InitializeLifetimeService()
{
return null;
}
}
所以这里究竟发生了什么,我怎样才能让它表现自己呢?我需要我创建的AppDomain加载我提供的程序集,然后从扩展程序获取它的同一位置加载它的依赖项(或至少foo.dll
),我想。或者至少我需要它知道我的透明代理是FooAssembly
。
编辑:我试图复制我的project.dll
到作为extension.dll
,使其不得不从同一位置加载相同的文件夹中。这并没有什么差别,所以我试着坚持这些线到我FooAssembly
构造:
System.Diagnostics.Debug.WriteLine(AppDomain.CurrentDomain.FriendlyName);
System.Diagnostics.Debug.WriteLine(this.GetType().FullName);
System.Diagnostics.Debug.WriteLine(this.GetType().Assembly.CodeBase);
而且我可以看到一个)我在创建的域。 b)我有合适的课程,c)我看起来有正确的道路?!?该CodeBase
回来为:
file:///C:/USERS/MATT.BURLAND/APPDATA/LOCAL/MICROSOFT/VISUALSTUDIO/14.0EXP/EXTENSIONS/SOMECO/FOOTOOLS/1.0/Foo.DLL
所以在我的默认域创建域之后,并试图创建一个对象之前,我这样做:
System.Diagnostics.Debug.WriteLine(AppDomain.CurrentDomain.FriendlyName);
System.Diagnostics.Debug.WriteLine(typeof(SpiderAssembly).FullName);
System.Diagnostics.Debug.WriteLine(typeof(SpiderAssembly).Assembly.CodeBase);
在这里,我的代码基础是:
file:///C:/USERS/MATT.BURLAND/APPDATA/LOCAL/MICROSOFT/VISUALSTUDIO/14.0EXP/EXTENSIONS/SOMECO/FOOTOOLS/1.0/foo.dll
这里唯一的区别是在壳体vs Foo.DLL
,我认为这不应该太重要。
我想这(通过this启发):
dynamic dobj = obj;
string l2 = dobj.GetType().Assembly.CodeBase;
System.Diagnostics.Debug.WriteLine(l2);
而且它清楚地认为它是从file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
加载MarshalByRefObject
,所以它好像它不能正确展开?
编辑:在阅读了更多有关这个,我有一个理论。对于要在域之间共享的foo.dll
,它必须加载“域中立”,而我目前的理论是我的扩展可能被视觉工作室隔离在它自己的域中,所以foo.dll
被更多代码加载,其方式是而不是域中立,这意味着我创建的应用程序域必须加载它自己的副本。这有任何意义吗?有没有办法解决这个问题?