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

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

问题描述

这是我的问题的基本要点:


  1. 我的主窗口类实例化A类。

  2. Class A在次要AppDomain 中实例化B类。

  3. B类引发事件,A类成功处理事件。

  4. A类引发了自己的事件。

问题:在步骤4中,当A类从捕获B类事件的事件处理程序方法引发其自己的事件时,会引发事件; 但是,不会调用Window类中的订阅处理程序。



没有抛出异常。如果我删除了二级AppDomain,事件得到处理没有问题。



有谁知道为什么这不工作?有没有另一种方法可以使这项工作不使用回调?



我会认为,如果有的话,问题会发生在步骤3而不是第4步。 >

这是一个真正的代码示例来说明问题:

  Class Window1 

私人WithEvents _prog作为危险程序

私有子按钮1_Click(ByVal发件人作为System.Object,ByVal e As System.Windows.RoutedEventArgs)处理Button1.Click
_prog =新DangerousProgram()
_prog.Name =坏程序
End Sub

Private Sub MyEventHandler(ByVal sender As Object,ByVal e As NameChangedEventArgs)处理_prog.NameChanged
TextBox1.Text =程序的名称现在是:& e.Name
End Sub

结束类


< Serializable()> _
公共类危险程序

私有_appDomain作为AppDomain
私有WithEvents _dangerousProgram作为程序
公共事件NameChanged(ByVal sender As Object,ByVal e As NameChangedEventArgs)


Public Sub New()

// DangerousPrograms是在自己的AppDomain内创建的,以实现安全。

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

End Sub


公共属性名称()As String
获取
返回_dangerousProgram.Name
结束Get
Set(ByVal value As String)
_dangerousProgram.Name = value
结束集
End Property


Public Sub NameChangedHandler(ByVal sender As Object,ByVal e As NameChangedEventArgs)处理_dangerousProgram.NameChanged
Debug.WriteLine(String.Format(Caught event in DangerousProgram程序名称为{0}。,e.Name))
Debug.WriteLine(重新提升事件...)

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

结束类


< Serializable()> _
公共类程序
继承MarshalByRefObject

私有_name As String
公共事件NameChanged(ByVal sender As Object,ByVal e As NameChangedEventArgs)

公共属性名称()As String
获取
返回_name
结束获取
设置(ByVal值As String)
_name = value
RaiseEvent NameChanged (Me,New NameChangedEventArgs(_name))
结束集
结束属性

结束类


< Serializable()> _
公共类NameChangedEventArgs
继承EventArgs

公共名称作为字符串

公共子新建(ByVal newName As String)
Name = newName
End Sub

结束类


解决方案

在我第一次尝试解决此问题时,我删除了 B类继承 MarshalByRefObject ,并将其标记为可序列化。结果是对象被值得封送,我刚刚得到一个在主机AppDomain中执行的 C类的副本。这不是我想要的。



我发现真正的解决方案是 B类 DangerousProgram <例子中的code)也应该继承自 MarshalByRefObject ,以便回调也使用代理将线程转换回默认AppDomain。



顺便说一句,这是一篇伟大的文章。我发现埃里克·利珀特(Eric Lippert)以一种非常聪明的方式通过引用元帅解释元帅的价值。


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:使用AppDomains提高和处理事件的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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