这有点复杂,但我会尽量让它变得清晰。我正在创建一个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);
我可以看到a)我在创建的域中。 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
这里唯一的区别是foo.dll
与Foo.DLL
的套管,我认为这不应该是重要的。
我试过这个(灵感来自this):
dynamic dobj = obj;
string l2 = dobj.GetType().Assembly.CodeBase;
System.Diagnostics.Debug.WriteLine(l2);
它显然认为它是MarshalByRefObject
从file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
加载的,所以它似乎没有正确展开?
编辑:在阅读了更多内容之后,我有一个理论。对于域之间共享的foo.dll
,它必须被加载为“域中立”,而我目前的理论是我的扩展可能被visual studio隔离在它自己的域中,因此foo.dll
被加载以不域中立的方式处理更多代码,这意味着我创建的应用程序域必须加载它自己的副本。这有任何意义吗?有办法吗?
答案 0 :(得分:1)
经过大量搜索并多次尝试重新排列代码后,当我找到ProvideBindingPathAttribute时,我最终破解了这一点。
我将[ProvideBindingPath]
添加到我的包类中,一直困扰着我的问题就消失了。我不再需要为我的域ApplicationBase
弄乱,并且可以为我的新AppDomain.CurrentDomain.SetupInformation
传递AppDomainSetup
{。}}。