2016-08-02 78 views
0

这有点复杂,但我会尽量使其尽可能清晰。我创建了一个Visual Studio扩展,当您右键单击某个项目(并且该项目符合某些条件)时,该菜单项会添加到上下文菜单中。菜单应该触发过程将:在Visual Studio扩展中创建域和加载程序集

1)建设项目

2)创建一个新的AppDomain

3)装载新组装成新的AppDomain

4)从第三个程序集中定义的新AppDomain中返回一些对象(即不是扩展程序集或构建的项目),但参考其他两个

我不断遇到的问题是使用数字4,并且说服扩展名从第三个程序集(我们称之为foo.dllFooAssembly)的类型是相同的类型。

在我的分机(我们称之为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.dllproject.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被更多代码加载,其方式是而不是域中立,这意味着我创建的应用程序域必须加载它自己的副本。这有任何意义吗?有没有办法解决这个问题?

回答

1

经过大量的搜索和多次尝试重新排列代码后,我终于在我发现ProvideBindingPathAttribute时破解了这个。

我将[ProvideBindingPath]添加到我的包类中,并且困扰我的问题消失了。我不再需要为我的网域搞乱ApplicationBase,只需通过AppDomain.CurrentDomain.SetupInformation即可获得我的新AppDomainAppDomainSetup