Question

J'ai deux domaines d'application, un des parents créant le domaine de l'enfance. Dans le domaine des enfants, il y a un objet MarshalByRef, étant en communication avec l'aide de .NET Remoting. Un objet en cours d'exécution dans le domaine parent appelle l'enveloppe de l'objet distant dans le cadre de la fonction de l'application:

public class ScanningTask : Task
{
    private class Loader : MarshalByRef
    {
        public void Load(IEnumerable<string> paths)
        {
            ...
        }

        public event EventHandler<LoadEventArgs> OnLoad;
    }

    public void RunTask()
    {
        var domain = AppDomain.CreateDomain("LoadDomain");

        var loader = (Loader)domain.CreateInstanceFromAndUnwrap(
            typeof(Loader).Assembly.Location,
            typeof(Loader).FullName);

        loader.Load(...);

        AppDomain.Unload(domain);
    }
}

Code plupart supprimés par souci de concision.

Cet objet Loader expose un événement OnLoad Je voudrais capturer dans le domaine parent. Si je viens d'ajouter un délégué de gestionnaire d'événements, il tente de sérialiser l'ScanningTask dans le domaine des enfants et lance une exception à ce sujet ne pas être sérialisable.

Ce que je veux vraiment est pour l'événement à communiquer à travers les domaines. Toutes les suggestions intelligentes quant à la façon?

Était-ce utile?

La solution

Basé sur cette solution , vous pourriez rendre votre Hériter des tâches de la classe des tâches de MarshalByRefObject ainsi. Cela résoudrait le problème de sérialisation comme il passerait une référence sérialisé entre domaines d'application qui serait utilisé pour attacher à l'événement.

public class ScanningTask : MarshalByRefObject
{
    private class Loader : MarshalByRefObject
    {
        public void Load()
        {
            if (OnLoad != null)
                OnLoad(this, EventArgs.Empty);
        }

        public event EventHandler OnLoad;
    }

    public void RunTask()
    {
        var domain = AppDomain.CreateDomain("LoadDomain");

        var loader = (Loader)domain.CreateInstanceFromAndUnwrap(
            typeof(Loader).Assembly.Location,
            typeof(Loader).FullName);

        loader.OnLoad += new EventHandler(loader_OnLoad);
        loader.Load();

        AppDomain.Unload(domain);
    }

    void loader_OnLoad(object sender, EventArgs e)
    {
        Console.Write("load event called");
    }
}

Si, pour des raisons de code existant de la classe de base de travail ne peut pas être fait pour hériter de MarshalByRefObject, votre solution pourrait être une classe proxy qui hérite de Loader (étant donc MarshalByRefObject lui-même) et transfère les appels à une instance déballés réelle.

public class ScanningTask
{
    private class Loader : MarshalByRefObject
    {
        public virtual void Load()
        {
            RaiseOnLoad(this);
        }

        protected void RaiseOnLoad(Loader loader)
        {
            if (OnLoad != null)
                OnLoad(loader, EventArgs.Empty);
        }

        public event EventHandler OnLoad;
    }

    private class LoaderProxy : Loader
    {
        public readonly Loader Instance;

        public LoaderProxy(Loader loaderInstance)
        {
            this.Instance = loaderInstance;
            this.Instance.OnLoad += new EventHandler((sender, e) => RaiseOnLoad(this.Instance));
        }

        public override void Load()
        {
            this.Instance.Load();
        }
    }

    public void RunTask()
    {
        var domain = AppDomain.CreateDomain("LoadDomain");

        var loader = (Loader)domain.CreateInstanceFromAndUnwrap(
            typeof(Loader).Assembly.Location,
            typeof(Loader).FullName);

        var proxy = new LoaderProxy(loader);
        proxy.OnLoad += new EventHandler(loader_OnLoad);
        loader.Load(); // same as proxy.Load()

        AppDomain.Unload(domain);
    }

    void loader_OnLoad(object sender, EventArgs e)
    {
        Console.Write("load event called");
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top