跨越AppDomains

时间:2016-07-28 17:35:48

标签: c# appdomain

我确定我的问题的根本原因是类似的问题:

How do I pass references as method parameters across AppDomains?

,特别是this answer,但我不太确定如何修复它。

我遇到的问题是,我有一个我正在编写的Visual Studio扩展,它需要做的一件事就是将一个程序集加载到一个单独的域中(所以我可以把它转储到我的'完成它)并用它做一些事情。所以我的域名设置如下:

// The actual ApplicationBase of the current domain will be the one of VS and not of my plugin
// We need our new AppDomain to be able to find our assemblies
var p = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var setup = new AppDomainSetup()
{
    ApplicationBase = p
};
domain = AppDomain.CreateDomain("MyTest_AppDomain", AppDomain.CurrentDomain.Evidence, setup);
var t = typeof(Proxy);
proxy = domain.CreateInstanceAndUnwrap(t.Assembly.FullName,
    t.FullName,
    false,
    BindingFlags.Default,
    null,
    new object[] { assemblyPath },
    null,
    null) as Proxy;

我需要设置ApplicationBase才能加载我的类Proxy,即使它与上面的代码在同一个程序集中定义。没有它,我得到FileNotFoundExceptions

现在我的Proxy课程看起来像这样:

public class Proxy : MarshalByRefObject
{
    private Assembly _assembly;

    private IEnumerable<Type> _types;

    public IEnumerable<Type> Types
    {
        get
        {
            if (_types == null && _assembly != null)
            {
                _spiders = _assembly.GetTypes().Where(t => typeof(IFoo).IsAssignableFrom(t)).ToList();
            }
            return _types;
        }
    }

    public Proxy(string assemblyPath)
    {
        _assembly = Assembly.LoadFile(assemblyPath);
    }

    public IFoo GetInstanceOf(string fooType)
    {
        var type = Types.FirstOrDefault(t => t.FullName == fooType);
        if (type == null)
        {
            throw new InvalidOperationException($"Unknown type {fooType} in assembly {_assembly.FullName}");
        }
        return GetInstanceOf(type);
    }
    private IFoo GetInstanceOf(Type fooType)
    {
        var obj = Activator.CreateInstance(fooType);
        return obj as IFoo;
    }

    public override object InitializeLifetimeService()
    {
        return null;
    }
}

回到创建新AppDomain的同一个班级和新ProxyAppDomain的实例我有类似这样的内容:

public IFoo GetInstanceOf(Type type)
{
    var name = type.FullName;
    var foo = proxy.GetInstanceOf(name);
    return foo;
}

最初我试图直接调用proxy.GetInstanceOf传递类型,但这可能不起作用,原因与我的代码不起作用的原因相同。当我到达var foo = proxy.GetInstanceOf...行时,我会收到一条ArgumentException,其中包含以下消息:

  

对象类型无法转换为目标类型。

我认为问题是因为IFoo中的MyTest_AppDomainIFoo中的DefaultDomain不一致IFoo,但我不确定解决这个问题的正确方法是。

可能相关的是MyTest_AppDomain本身是在单独的第三个程序集中定义的,我的VSIX项目和我尝试在单独域中加载的程序集都在引用。我想,我需要说服IFoo从与DefaultDomain相同的位置加载相同的IFoo程序集,或者说服它们是同一个。

注意:我实现FooBase的所有类都继承自一个自己继承自MarshalByRefObject的抽象基础_assembly = Assembly.LoadFile(assemblyPath);

编辑更多地考虑这个问题可能来自这里:

assemblyPath

ApplicationBase foo.dll的路径不同,该路径拥有自己的IFoo版本(其中ApplicationBase已定义)。也许它是从Proxy.GetInstanceOf加载之前从那里加载的?在typeof(IFoo).Assembly.Location我可以查看ApplicationBase,它会给我foo.dll中设置的预期路径,但我不认为我的程序集加载它时会从export PATH=${PATH}:${DTITK_ROOT}/bin:${DTITK_ROOT}/utilities:${DTITK_ROOT}/scripts 获取$images=image::findorFail($id);那里。

1 个答案:

答案 0 :(得分:1)

我为你准备了一份快速工作的样本。这就是你所期望的,IFoo由参考调用者编组。

using System;
using System.Reflection;

namespace AppdomainTesting
{
    class Program
    {
        static void Main(string[] args)
        {
            var p = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var setup = new AppDomainSetup()
            {
                ApplicationBase = p
            };
            IProxy proxy;
            var domain = AppDomain.CreateDomain("MyTest_AppDomain", AppDomain.CurrentDomain.Evidence, setup);
                var t = typeof(Proxy);
            proxy = domain.CreateInstanceAndUnwrap(t.Assembly.FullName,
                t.FullName,
                false,
                BindingFlags.Default,
                null,
                null,
                null,
                null) as IProxy;

            // works
            var typeofFoo = typeof(Foo);
            var foo = proxy.GetFoo(new TypeDef() { Asembly = typeofFoo.Assembly.FullName, FullTypeName = typeofFoo.FullName });
            Console.WriteLine(foo.Domain);

            // Type also implements Serializable attribute (my mistake, I thought it did not)
            foo = proxy.GetFoo(typeofFoo);
            Console.WriteLine(foo.Domain);

            Console.WriteLine();
            Console.WriteLine("ENTER to exit");
            Console.ReadLine();
        }
    }

    public interface IFoo
    {
        string Domain { get; }
    }

    public class Foo : MarshalByRefObject, IFoo
    {
        public string Domain
        {
            get { return System.AppDomain.CurrentDomain.FriendlyName; }
        }
    }
    public interface IProxy
    {
        IFoo GetFoo(TypeDef typeToGet);
        IFoo GetFoo(Type type);
    }
    [Serializable]
    public class TypeDef
    {
        public string Asembly { get; set; }
        public string FullTypeName { get; set; }
    }

    public class Proxy : MarshalByRefObject, IProxy
    {
        public IFoo GetFoo(TypeDef typeToGet)
        {
            var type = Type.GetType(typeToGet.FullTypeName + ", " + typeToGet.Asembly, true);
            var instance = Activator.CreateInstance(type) as IFoo;
            return instance;
        }
        public IFoo GetFoo(Type type)
        {
            var instance = Activator.CreateInstance(type) as IFoo;
            return instance;
        }
    }
}