проблемы с событиями между доменами приложений

Я использую следующий вспомогательный класс с 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=neutral, PublicKeyToken=null" или одну из ее зависимостей. Система не может найти указанный файл.

Это должно быть связано с попыткой установить связь между AppDomains. Не совсем уверен, что делать. Нужно ли регистрировать «MyAssemblyName» в отдельном домене приложений, используемом для Pos для .Net?

Я использую призму, поэтому некоторые модули загружаются во время выполнения (в подпапке в моем выходном каталоге)... включая тот, в котором я использую последний фрагмент кода выше (Scanner = PosHelper.GetHardware....)


person Chris Klepeis    schedule 05.09.2012    source источник
comment
Кстати, я не думаю, что вам следует добавлять сериализуемый атрибут в MarshalByRefObject. Сериализуемые объекты должны передаваться из одного домена приложения в другой. Объекты на основе MarshalByRefObject остаются в своем AppDomain, и все взаимодействие происходит через прокси-объекты, прозрачно созданные механизмом .NET Remoting.   -  person Panos Rontogiannis    schedule 26.09.2012


Ответы (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 для передачи данных... и других подобных решений.

person Chris Klepeis    schedule 05.09.2012
comment
Эту статью интересно читать!! Ознакомьтесь с моей статьей об отправке событий через домен приложения blog.vcillusion. co.in/ Надеюсь, это поможет! - person vCillusion; 30.05.2018