我将以下助手类与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命名管道来传递数据。。。以及其他类似的解决方案。