Frage

Ich habe zwei App -Domänen, ein Elternteil erstellt die untergeordnete Domäne. Im Kinderbereich gibt es a MarshalByRef Objekt, mit der Verwendung von .NET Remoting kommuniziert werden. Ein in der übergeordneter Domäne ausgeführter Objekt ruft den Wrapper für das Remote -Objekt als Teil der Funktion der Anwendung auf:

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);
    }
}

Der meiste Code wurde für die Kürze entfernt.

Dies Loader Objekt enthüllt eine OnLoad Ereignis würde ich gerne in der übergeordneten Domäne erfassen. Wenn ich nur einen Event -Handler -Delegierten hinzufüge, versucht es, das zu serialisieren ScanningTask in die Kinderdomäne und wirft eine Ausnahme darüber, dass es nicht serialisierbar ist.

Was ich wirklich möchte, ist, dass die Veranstaltung über die Domänen kommuniziert wird. Irgendwelche cleveren Vorschläge, wie?

War es hilfreich?

Lösung

Bezogen auf diese Lösung, Sie können Ihre Aufgabenklassenaufgabe auch von MarshalbyrefObject erben. Dies würde das Serialisierungsproblem lösen, da es eine serialisierte Cross-App-Apparized-Referenz übergeben würde, die zum Anhängen an das Ereignis verwendet wird.

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");
    }
}

Wenn aus vorhandenen Codebasisgründen die Basisklassenaufgabe nicht zur Erben von MarshalbyrefObject erfolgen kann, könnte Ihre Lösung eine Proxy -Klasse sein, die von Loader (daher ein MarshalbyrefObject selbst ist) erbt und die Anrufe an eine tatsächliche ausgepackte Instanz weiterleiten.

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");
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top