跨AppDomain事件问题



我将以下助手类与POSfor.Net一起使用,以在单独的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扫描仪扫描数据时,我要处理一个基本类。在那个类中,我有一个事件,我想在扫描数据时激发它。这里有一个片段:

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添加到DataScaned事件的行时,我得到了以下错误:

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

这必须与尝试在AppDomains之间进行通信有关。不知道该怎么办。我需要在用于Pos for.Net的单独AppDomain中注册"MyAssemblyName"吗?

我使用棱镜,所以一些模块在运行时加载(在我的输出目录中的子文件夹中)。。。包括我使用上面最后一个代码片段的那个(Scanner=PosHelper.GetHardware….)

我相信我解决了我的问题。由于我的棱镜模块在运行时加载在一个子目录中,我需要将其添加到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命名管道来传递数据。。。以及其他类似的解决方案。

最新更新