跨 AppDomain 传递自定义对象

Posted

技术标签:

【中文标题】跨 AppDomain 传递自定义对象【英文标题】:Passing custom object across AppDomains 【发布时间】:2011-12-06 21:32:09 【问题描述】:

我编译了一个插件,然后在一个新的 AppDomain 中创建它的一个实例。然后我想在插件对象中执行一个方法,但这会导致 ArgumentException

    "Object of type System.MarshalByRefObject can not be converted to type Data"

下面的代码应该是可编译的并导致上面的异常。要使其正常工作,您还必须签署程序集(项目 -> 属性 -> 签名 -> 签署程序集 -> 新建 ...)

IPlugin.cs:

using System;

namespace Plugin

    [Serializable]
    class Data : MarshalByRefObject
    
        int value;
    

    interface IPlugin
    
        void DoStuff(Data data);
    

程序.cs:

using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Security.Policy;
using System.Security;
using System.Security.Permissions;
using System.Reflection;

namespace Plugin

    class Program
    
        public class Sandbox : MarshalByRefObject
        
            const string BaseDirectory = "Untrusted";
            const string DomainName = "Sandbox";
            private object instance;

            public static Sandbox Create()
            
                var setup = new AppDomainSetup()
                
                    ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaseDirectory),
                    ApplicationName = DomainName,
                    DisallowBindingRedirects = true,
                    DisallowCodeDownload = true,
                    DisallowPublisherPolicy = true
                ;

                Evidence ev = new Evidence();
                ev.AddHostEvidence(new Zone(SecurityZone.Internet));

                var permissions = new PermissionSet(PermissionState.None);
                permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
                permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

                StrongName fullTrustAssembly = typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>();

                var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions, fullTrustAssembly);

                return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap();
            

            public bool CreateInstance(string assemblyPath, string scriptType)
            
                new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert();
                var assembly = Assembly.LoadFrom(assemblyPath);
                CodeAccessPermission.RevertAssert();

                Type type = assembly.GetType(scriptType);
                if (type == null)
                    return false;

                instance = Activator.CreateInstance(type);

                return instance != null;
            

            public object Execute(string method, params object[] parameters)
            
                Type type = instance.GetType();
                MethodInfo info = type.GetMethod(method);
                return info.Invoke(instance, parameters);
            
        

        private static void CompileToFile(string code, string ifaceFile, string output)
        
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

            CompilerParameters p = new CompilerParameters();
            p.GenerateInMemory = false;
            p.GenerateExecutable = false;
            p.OutputAssembly = output;

            provider.CompileAssemblyFromSource(p, code, ifaceFile);
        

        private static string code = @"
using Plugin;
class MyPlugin : IPlugin

    public void DoStuff(Data data)
    
    

";

        static void Main(string[] args)
        
            string iface = System.IO.File.ReadAllText(@"C:\Documents and Settings\markus.BLUE\mina dokument\visual studio 2010\Projects\Plugin\Plugin\IPlugin.cs");
            string pluginObjectFile = System.IO.Path.GetTempFileName();
            CompileToFile(code, iface, pluginObjectFile);

            Sandbox s = Sandbox.Create();
            s.CreateInstance(pluginObjectFile, "MyPlugin");

            Data data = new Data();
            s.Execute("DoStuff", data);
        
    

【问题讨论】:

考虑更新示例,以便它实际使用您的对象而不是通用反射代码。并命名参数,以便清楚每个对象所在的位置。 您在两个程序集中都定义了 Data 类吗?尝试将它放在一个单独的程序集中并从其他程序集中引用第三个程序集,事实上,一旦它在需要使用它的所有程序集可用(引用)的地方定义,你就不需要将它转换为任何东西。 戴维德:这确实有效!谢谢! 或者不是真的......它看起来很有效,但是当我尝试更改传递的 Data 对象时,我遇到了安全异常。 【参考方案1】:

它必须是通信双方都知道的类型!

【讨论】:

Data 类是在两边都定义的,所以它在两边都是已知的类型。但是即使两种类型相同,它似乎也不愿意转换它。

以上是关于跨 AppDomain 传递自定义对象的主要内容,如果未能解决你的问题,请参考以下文章

跨 AppDomain 边界的垃圾收集对象

将代理对象克隆到当前 AppDomain

通过方法通道颤振传递自定义对象

使用自定义对象时在活动android之间传递数据时出错

在两个 iOS 应用程序之间传递自定义对象

如何跨 AppDomain 将引用作为方法参数传递?