【问题标题】:Mixing MarshalByRefObject and Serializable混合 MarshalByRefObject 和 Serializable
【发布时间】:2012-01-07 22:57:49
【问题描述】:

各种来源解释了这一点

当一个对象从 MarshalByRefObject 派生时,一个对象引用 将从一个应用程序域传递到另一个应用程序域,而不是 对象本身。当一个对象被标记为 [Serializable] 时, 对象将被自动序列化,从一个传输 应用程序域到另一个,然后反序列化以产生一个 第二个应用程序域中对象的精确副本。然后注意 当 MarshalByRefObject 传递一个引用时,[Serializable] 导致对象被复制。 [source]

我正在设计我的第一个使用 AppDomains 的应用程序,我想知道当您将 MarshalByRefObjects 的引用放在不实现 MarshalByRefObject 的可序列化对象中时会发生什么,因为到目前为止我找不到关于该主题的任何文档.

例如,如果我尝试返回 List<MBR> 其中 MBR : MarshalByRefObject 跨越 AppDomain 边界会发生什么?我是否得到List<MBR> 的副本,其中每个MBR 是原始对象的TransparentProxy?有没有关于混合这两种机制的技术细节的文档?

【问题讨论】:

    标签: .net serialization remoting appdomain marshalbyrefobject


    【解决方案1】:

    我刚刚对List<MBR> 进行了快速测试,它似乎可以正常工作:

    public class MBR : MarshalByRefObject
    {
        List<MBR> _list;
        public MBR() { _list = new List<MBR> { this }; }
        public IList<MBR> Test() { return _list; }
        public int X { get; set; }
    }
    
    // Later...
    var mbr = AppDomainStarter.Start<MBR>(@"C:\Program Files", "test", null, true);
    var list = mbr.Test();
    list[0].X = 42;
    list.Clear();
    Debug.WriteLine(string.Format("X={0}, Count={1}", mbr.X, mbr.Test().Count));
    

    输出为X=42, Count=1,调试器显示List&lt;MBR&gt; 包含__TransparentProxy。很明显,MarshalByRefObject 在另一个按值封送的对象中通过引用成功封送。

    如果有人能找到,我仍然希望查看文档或技术细节。

    对于任何好奇的人,我编写了这个方便的沙盒 AppDomainStarter:

    /// <summary><see cref="AppDomainStarter.Start"/> starts an AppDomain.</summary>
    public static class AppDomainStarter
    {
        /// <summary>Creates a type in a new sandbox-friendly AppDomain.</summary>
        /// <typeparam name="T">A trusted type derived MarshalByRefObject to create 
        /// in the new AppDomain. The constructor of this type must catch any 
        /// untrusted exceptions so that no untrusted exception can escape the new 
        /// AppDomain.</typeparam>
        /// <param name="baseFolder">Value to use for AppDomainSetup.ApplicationBase.
        /// The AppDomain will be able to use any assemblies in this folder.</param>
        /// <param name="appDomainName">A friendly name for the AppDomain. MSDN
        /// does not state whether or not the name must be unique.</param>
        /// <param name="constructorArgs">Arguments to send to the constructor of T,
        /// or null to call the default constructor. Do not send arguments of 
        /// untrusted types this way.</param>
        /// <param name="partialTrust">Whether the new AppDomain should run in 
        /// partial-trust mode.</param>
        /// <returns>A remote proxy to an instance of type T. You can call methods 
        /// of T and the calls will be marshalled across the AppDomain boundary.</returns>
        public static T Start<T>(string baseFolder, string appDomainName, 
            object[] constructorArgs, bool partialTrust)
            where T : MarshalByRefObject
        {
            // With help from http://msdn.microsoft.com/en-us/magazine/cc163701.aspx
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = baseFolder;
    
            AppDomain newDomain;
            if (partialTrust) {
                var permSet = new PermissionSet(PermissionState.None);
                permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
                permSet.AddPermission(new UIPermission(PermissionState.Unrestricted));
                newDomain = AppDomain.CreateDomain(appDomainName, null, setup, permSet);
            } else {
                newDomain = AppDomain.CreateDomain(appDomainName, null, setup);
            }
            return (T)Activator.CreateInstanceFrom(newDomain, 
                typeof(T).Assembly.ManifestModule.FullyQualifiedName, 
                typeof(T).FullName, false,
                0, null, constructorArgs, null, null).Unwrap();
        }
    }
    

    【讨论】:

      【解决方案2】:

      据我了解,只有传递的顶层对象可能是MBR。在你的场景中,由于 List 不是 MBR,所以当它越过边界时,你会收到序列化的副本。

      MSDN documentation 中的这一部分解释了这种行为:

      MarshalByRefObject 是对象的基类,这些对象通过使用代理交换消息来跨应用程序域边界进行通信。不从 MarshalByRefObject 继承的对象是按值隐式编组的。当远程应用程序按值引用编组对象时,该对象的副本将跨应用程序域边界传递。

      所以,由于传递的类(List)不是MBR,它会和它的内容一起被序列化。

      此外,虽然不直接适用于问题,但需要注意以下行为:

      ...对象的成员在创建它们的应用程序域之外不可用。

      【讨论】:

      • 所以如果 MBR 不可序列化,当 .NET Framework 尝试序列化它时会出现某种异常?返回 MBR[] 数组怎么样? System.Array 是可序列化的,而不是从 MarshalByRefObject 派生的。
      • re 不可序列化:是的,运行时会发生异常。重新 MBR 数组:您遇到与 List 相同的问题,因为数组是顶级类。
      • 实验表明,可序列化容器内的不可序列化 MBR 无一例外地通过引用传递。
      猜你喜欢
      • 1970-01-01
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 2012-11-30
      • 1970-01-01
      • 2016-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多