.NET:问题的提出和处理使用应用程序域事件 [英] .NET: Problem with raising and handling events using AppDomains

查看:135
本文介绍了.NET:问题的提出和处理使用应用程序域事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我的问题的基本要点是:

  1. 在我的主窗口类实例化的类。
  2. A类实例化B级在中学的AppDomain
  3. 在B类引发事件和A级成功处理该事件。
  4. 在A级提高自身的事件。

问题:在步骤4,当一个类提高其的的距离,引起了B类的事件的事件处理程序方法事件,引发该事件; 但是,在Window类订阅处理程序不会被调用。

有没有异常被抛出。如果我删除辅助的AppDomain,该事件得到没有问题的处理。

有谁知道为什么不起作用?有另一种方式来完成这项工作,而无需使用回调?

我会想,如果有的话,会发生,而不是第4步第3步的问题。

下面是一个真正的code样本来说明这个问题:

 类窗口1

    私人WithEvents就_PROG作为DangerousProgram

    私人小组的button1_Click(BYVAL发件人为System.Object的,BYVAL E上System.Windows.RoutedEventArgs)处理Button1.Click
        _PROG =新DangerousProgram()
        _prog.Name =坏程序
    结束小组

    私人小组MyEventHandler(BYVAL发件人为对象,BYVAL E上NameChangedEventArgs)处理_prog.NameChanged
        TextBox1.Text =节目的名称现在是:&放大器; e.Name
    结束小组

末级


<序列化()> _
公共类DangerousProgram

    私人_appDomain作为应用程序域
    私人WithEvents就_dangerousProgram作为计划
    公共事件NameChanged(BYVAL发件人为对象,BYVAL E上NameChangedEventArgs)


    公共子新()

        // DangerousPrograms在里面自己的AppDomain安全创建。

        _appDomain = AppDomain.CreateDomain(应用程序域)
        昏暗组装的String = System.Reflection.Assembly.GetEntryAssembly()。全​​名
        _dangerousProgram = CTYPE(_
                    _appDomain.CreateInstanceAndUnwrap(组装,_
                        的GetType(程序).FullName),程序)

    结束小组


    公共属性Name()作为字符串
        得到
            返回_dangerousProgram.Name
        最终获取
        设置(BYVAL值作为字符串)
            _dangerousProgram.Name =价值
        结束设定
    高端物业


    公用Sub NameChangedHandler(BYVAL发件人为对象,BYVAL E上NameChangedEventArgs)处理_dangerousProgram.NameChanged
        的Debug.WriteLine(的String.Format(在DangerousProgram。程序名抓事件{0},e.Name))
        的Debug.WriteLine(再筹款活动......)

        的RaiseEvent NameChanged(ME,新NameChangedEventArgs(e.Name))
    结束小组

末级


<序列化()> _
公共类节目
    继承MarshalByRefObject的

    私人_name作为字符串
    公共事件NameChanged(BYVAL发件人为对象,BYVAL E上NameChangedEventArgs)

    公共属性Name()作为字符串
        得到
            返回_name
        最终获取
        设置(BYVAL值作为字符串)
            _name =价值
            的RaiseEvent NameChanged(ME,新NameChangedEventArgs(_name))
        结束设定
    高端物业

末级


<序列化()> _
公共类NameChangedEventArgs
    继承EventArgs的

    公共名称作为字符串

    公共子新(BYVAL了newName作为字符串)
        NAME =了newName
    结束小组

末级
 

解决方案

在我第一次尝试解决这个问题,我删除 B类的继承 MarshalByRefObject的并标记它作为序列化代替。其结果是该对象编组按价值计算,我刚刚得到的复印件 C类的执行主机的AppDomain。这不是我想要的。

真正的解决办法,我发现,是 B类 DangerousProgram 中的例子)也应该从继承MarshalByRefObject的,以便在再打还采用了代理过渡线程返回到默认的AppDomain。

另外,这里是一个伟大的文章我发现埃里克利珀,在一个非常聪明的方式解释了名帅由参与元帅按价值计算。

Here is the basic gist of my problem:

  1. My main Window class instantiates Class A.
  2. Class A instantiates Class B in a secondary AppDomain.
  3. Class B raises an event and Class A handles the event successfully.
  4. Class A raises an event of its own.

Problem: In step 4, when Class A raises its own event from the event handler method that caught Class B's event, the event is raised; however, the subscribing handler in the Window class is never called.

There are no exceptions being thrown. If I remove the secondary AppDomain, the event gets handled without a problem.

Does anyone know why this doesn't work? Is there another way to make this work without using a callback?

I would think, if anything, the problem would occur in step 3 instead of step 4.

Here's a real code sample to illustrate the problem:

Class Window1

    Private WithEvents _prog As DangerousProgram    

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click    
        _prog = New DangerousProgram()
        _prog.Name = "Bad Program"  
    End Sub

    Private Sub MyEventHandler(ByVal sender As Object, ByVal e As NameChangedEventArgs) Handles _prog.NameChanged
        TextBox1.Text = "Program's name is now: " & e.Name
    End Sub

End Class


<Serializable()> _    
Public Class DangerousProgram

    Private _appDomain As AppDomain
    Private WithEvents _dangerousProgram As Program
    Public Event NameChanged(ByVal sender As Object, ByVal e As NameChangedEventArgs)


    Public Sub New()

        // DangerousPrograms are created inside their own AppDomain for security.

        _appDomain = AppDomain.CreateDomain("AppDomain")    
        Dim assembly As String = System.Reflection.Assembly.GetEntryAssembly().FullName 
        _dangerousProgram = CType( _   
                    _appDomain.CreateInstanceAndUnwrap(assembly, _    
                        GetType(Program).FullName), Program)

    End Sub


    Public Property Name() As String
        Get
            Return _dangerousProgram.Name
        End Get
        Set(ByVal value As String)
            _dangerousProgram.Name = value
        End Set
    End Property


    Public Sub NameChangedHandler(ByVal sender As Object, ByVal e As NameChangedEventArgs) Handles _dangerousProgram.NameChanged    
        Debug.WriteLine(String.Format("Caught event in DangerousProgram. Program name is {0}.", e.Name))
        Debug.WriteLine("Re-raising event...")

        RaiseEvent NameChanged(Me, New NameChangedEventArgs(e.Name))   
    End Sub

End Class


<Serializable()> _    
Public Class Program
    Inherits MarshalByRefObject

    Private _name As String
    Public Event NameChanged(ByVal sender As Object, ByVal e As NameChangedEventArgs)

    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
            RaiseEvent NameChanged(Me, New NameChangedEventArgs(_name))
        End Set
    End Property   

End Class


<Serializable()> _   
Public Class NameChangedEventArgs
    Inherits EventArgs

    Public Name As String

    Public Sub New(ByVal newName As String)
        Name = newName
    End Sub

End Class

解决方案

In my first attempt at solving this issue, I removed Class B's inheritance of MarshalByRefObject and flagged it as serializable instead. The result was the the object was marshaled by value and I just got a copy of Class C that executes in the host AppDomain. This is not what I wanted.

The real solution, I found, was that Class B (DangerousProgram in the example) should also inherit from MarshalByRefObject so that the call back also uses a proxy to transition the thread back to the default AppDomain.

By the way, here's a great article I found by Eric Lippert that explains marshal by ref vs. marshal by value in a very clever way.

这篇关于.NET:问题的提出和处理使用应用程序域事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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