如何在应用程序域之间传递事件? [英] How do I communicate an event between App Domains?

查看:244
本文介绍了如何在应用程序域之间传递事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个应用程序域,一个父级创建子域。在子域中,有一个 MarshalByRef 对象,与使用.NET Remoting进行通信。在父域中运行的对象在应用程序的功能中调用远程对象的包装器:

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

public event EventHandler< LoadEventArgs>负载;
}

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

为了简洁起见,删除了大部分代码。 em>



这个 Loader 对象暴露了一个 OnLoad 事件我想在父域中捕获。如果我只是添加一个事件处理程序委托,它会尝试将 ScanningTask 序列化到子域中,并引发一个不可序列化的异常。



我真正想要的是在整个域间传送事件。任何关于如何的聪明的建议?

解决方案

根据这个解决方案,你也可以使你的Task类任务从MarshalByRefObject继承。这将解决序列化问题,因为它会传递一个跨AppDomain序列化引用,用于附加事件。

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

公共事件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);
}
}

如果对于现有的代码库原因,基类任务不能从MarshalByRefObject继承,您的解决方案可能是从Loader继承的代理类(因此是一个MarshalByRefObject本身),并将调用转发到一个实际的解包实例。

  public class ScanningTask 
{
private class Loader:MarshalByRefObject
{
public virtual void Load()
{
RaiseOnLoad这个);


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

公共事件EventHandler OnLoad;
}

私有类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(); //与proxy.Load()相同

AppDomain.Unload(domain);
}

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


I have two app domains, one parent creating the child domain. In the child domain, there is a MarshalByRef object, being communicated with using .NET Remoting. An object running in the parent domain invokes the wrapper for the remote object as part of the application's function:

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

Most code removed for brevity.

This Loader object exposes an OnLoad event I'd like to capture in the parent domain. If I just add an event handler delegate, it tries to serialize the ScanningTask into the child domain and throws an exception about it not being serializable.

What I really want is for the event to be communicated across the domains. Any clever suggestions as to how?

解决方案

Based on this solution, you could make your Task class task inherit from MarshalByRefObject as well. This would solve the serialization issue as it would pass a cross-AppDomain serialized reference which would be used to attach to the event.

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

If for existing codebase reasons the base class Task cannot be made to inherit from MarshalByRefObject, your solution could be a proxy class that inherits from Loader (therefore being a MarshalByRefObject itself) and forwards calls to an actual unwrapped instance.

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

这篇关于如何在应用程序域之间传递事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆