跨 AppDomain 事件问题

Posted

技术标签:

【中文标题】跨 AppDomain 事件问题【英文标题】:cross-AppDomain event issues 【发布时间】:2012-09-05 01:19:00 【问题描述】:

我在 .Net 的 POS 中使用以下帮助程序类来获取对单独 AppDomain 中硬件的引用(绕过需要 <NetFx40_LegacySecurityPolicy enabled="true"/> 的一些限制

public static class PosHelper

    private static AppDomain _posAppDomain  get; set; 

    private static AppDomain PosAppDomain
    
        get
        
            if (_posAppDomain == null)
            
                AppDomainSetup currentAppDomainSetup = AppDomain.CurrentDomain.SetupInformation;
                AppDomainSetup newAppDomainSetup = new AppDomainSetup()
                
                    ApplicationBase = currentAppDomainSetup.ApplicationBase,
                    LoaderOptimization = currentAppDomainSetup.LoaderOptimization,
                    ConfigurationFile = currentAppDomainSetup.ConfigurationFile
                ;
                newAppDomainSetup.SetCompatibilitySwitches(new[]  "NetFx40_LegacySecurityPolicy" );

                _posAppDomain = AppDomain.CreateDomain("POS Hardware AppDomain", null, newAppDomainSetup);
            
            return _posAppDomain;
        
    

    public static T GetHardware<T>() where T : PosHardware, new()
    
        T hardware = (T)PosAppDomain.CreateInstanceFromAndUnwrap(Assembly.GetAssembly(typeof(T)).Location, typeof(T).FullName);

        hardware.FindAndOpenDevice();
        return hardware;
    

当 POS 扫描仪扫描数据时,我有一个基本类要处理。在该课程中,我有一个要在扫描数据时触发的事件。这是一个sn-p:

public class ScannerDevice : PosHardware

    public event Action<string> DataScanned;
    ...
        _scanner.DataEvent += new DataEventHandler(Scanner_DataEvent);
    ...
    private void Scanner_DataEvent(object sender, DataEventArgs e)
    
        ASCIIEncoding encoder = new ASCIIEncoding();

        if (DataScanned != null)
            DataScanned(encoder.GetString(_scanner.ScanDataLabel));

        _scanner.DataEventEnabled = true; // enable for subsequent scans
    

请注意,PosHardware 抽象类继承 MarshalByRefObject 并标记为 [Serializable] 在我的主 AppDomain 中,我尝试像这样使用事件:

    Scanner = PosHelper.GetHardware<ScannerDevice>();
    Scanner.DataScanned += m =>
    
        Debug.WriteLine(m);
    ;

当它遇到尝试将 lambda 添加到 DataScanned 事件的行时,我收到此错误:

无法加载文件或程序集 'MyAssemlyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 或其依赖项之一。这 系统找不到指定的文件。

这必须与尝试在 AppDomain 之间进行通信有关。不太确定该怎么做。我需要在用于 Pos for .Net 的单独 AppDomain 中注册“MyAssemblyName”吗?

我使用 prism,因此在运行时会加载一些模块(在我的输出目录的子文件夹中)...包括我使用上面最后一个代码 sn-p 的那个(Scanner = PosHelper.GetHardware .... )

【问题讨论】:

顺便说一句,我认为您不应该在 MarshalByRefObject 上添加可序列化属性。可序列化对象应该是从一个 AppDomain 传递到另一个的对象。基于 MarshalByRefObject 的对象保留在其 AppDomain 上,并且整个通信是通过 .NET Remoting 机制透明创建的代理对象进行的。 【参考方案1】:

我相信我解决了我的问题。由于我的 prism 模块是在运行时在子目录中加载的,因此我需要将其添加到 AppDomain 中,以便 AppDomain 可以在子目录文件夹中找到程序集。:

PrivateBinPath = @"Modules"

http://msdn.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx

编辑

这只是部分解决了我的问题。我还必须重写 InitializeLifetimeService() 并返回 null,这样我的 MarshalByRefObject 就不会在程序运行时被释放(我相信默认超时是 5 分钟)。

另外,这现在可以工作了:

Scanner.DataScanned += m =>
    
        Debug.WriteLine(m);
    

但是当我尝试这样的事情时

Scanner.DataScanned += m =>
    
        DoSomething(m);
    

DoSomething 不在 Serializable 和 MarshalByRefObject 类中的地方,它会出错,因为 AppDomain 之间的通信中使用的所有类都需要这些类。所以我现在正在研究使用 WCF 命名管道来传递数据......以及其他类似的解决方案。

【讨论】:

这篇文章读起来很刺激!!查看我关于跨 AppDomain 发送事件的文章blog.vcillusion.co.in/…希望对您有所帮助!

以上是关于跨 AppDomain 事件问题的主要内容,如果未能解决你的问题,请参考以下文章

跨 AppDomain 边界的垃圾收集对象

跨AppDomain通信问题

跨 AppDomain 的自定义序列化

如何跨 AppDomains 订阅事件(object.Event += handler;)

跨 AppDomain 传递自定义对象

跨 appdomain 的静态类变量