Кросс-доменные проблемы
Я использую следующий вспомогательный класс с POS для.Net, чтобы получить ссылку на оборудование в отдельном домене приложений (обойдя некоторые ограничения, требующие <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);
};
Когда он попадает в строку, пытаясь добавить лямбду к событию DataScanned, я получаю эту ошибку:
Не удалось загрузить файл или сборку 'MyAssemlyName, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken=null' или одну из ее зависимостей. Система не может найти указанный файл.
Это должно быть связано с попыткой установить связь между доменами приложений. Не совсем уверен, что делать. Нужно ли регистрировать "MyAssemblyName" в отдельном домене приложений, используемом для Pos для.Net?
Я использую призму, поэтому некоторые модули загружаются во время выполнения (в подпапке моего выходного каталога)... включая тот, в котором я использую последний фрагмент кода выше (Scanner = PosHelper.GetHardware....)
1 ответ
Я считаю, что я решил свою проблему. Поскольку мои призменные модули загружаются во время выполнения в подкаталоге, мне нужно было добавить это в домен приложений, чтобы домен приложений мог находить сборки в папке подкаталогов.
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 для передачи данных... и других подобных решений.