【问题标题】:Passing custom object across AppDomains跨 AppDomain 传递自定义对象
【发布时间】: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 对象时,我遇到了安全异常。

标签: c# serialization appdomain


【解决方案1】:

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

【讨论】:

  • Data 类是在两边都定义的,所以它在两边都是已知的类型。但是即使两种类型相同,它似乎也不愿意转换它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
  • 2012-09-30
相关资源
最近更新 更多