Смешивание MarshalByRefObject и Serializable - PullRequest
6 голосов
/ 08 января 2012

Различные источники объясняют, что

Когда объект получает форму MarshalByRefObject, ссылка на объект будет передаваться из одного домена приложения в другой, а не сам объект. Когда объект помечен как [Сериализуемый], объект будет автоматически сериализован, перенесен с одного домен приложения к другому, а затем десериализовать для создания точная копия объекта во втором домене приложения. Обратите внимание, то что в то время как MarshalByRefObject передает ссылку, [Serializable] вызывает копирование объекта. [источник]

Я проектирую свое первое приложение, которое использует домены приложений, и мне интересно, что происходит, когда вы помещаете ссылки на MarshalByRefObjects внутри сериализуемых объектов, которые не реализуют MarshalByRefObject, потому что до сих пор я не могу найти какую-либо документацию по этому вопросу .

Например, что произойдет, если я попытаюсь вернуть List<MBR>, где MBR : MarshalByRefObject через границу AppDomain? Получу ли я копию List<MBR>, где каждый MBR является TransparentProxy для исходного объекта? И есть ли документация о технических деталях смешения двух механизмов?

Ответы [ 2 ]

7 голосов
/ 08 января 2012

Я только что сделал быстрый тест с 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<MBR> содержит__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();
    }
}
0 голосов
/ 08 января 2012

Насколько я понимаю, только передаваемый объект верхнего уровня может быть MBR.В вашем сценарии, поскольку List не является MBR, при его передаче за границу вы будете получать сериализованные копии.

В этом разделе документации MSDN объясняется такое поведение:

MarshalByRefObject - это базовый класс для объектов, которые взаимодействуют через границы домена приложения путем обмена сообщениями с использованием прокси.Объекты, которые не наследуются от MarshalByRefObject, неявно распределяются по значению.Когда удаленное приложение ссылается на маршал по значению объекта, копия объекта передается через границы домена приложения.

Итак, поскольку передаваемый класс (List) не является MBR, он будетСериализовано вместе с его содержимым.

Кроме того, хотя это не относится непосредственно к вопросу, очень важно отметить следующее поведение:

... члены объектане может использоваться вне домена приложения, в котором они были созданы.

...