跨 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 事件问题的主要内容,如果未能解决你的问题,请参考以下文章