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

Използвам следния помощен клас с POS за .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);
    };

Когато достигне линията, опитвайки се да добави ламбда към събитието DataScanned, получавам тази грешка:

Не може да се зареди файл или сборка „MyAssemlyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null“ или една от неговите зависимости. Системата не може да намери посочения файл.

Това трябва да е свързано с опит за комуникация между AppDomains. Не съм сигурен какво да правя. Трябва ли да регистрирам „MyAssemblyName“ в отделния AppDomain, използван за Pos за .Net?

Използвам prism, така че някои модули се зареждат по време на изпълнение (в подпапка в изходната ми директория)... включително този, в който използвам последния кодов фрагмент по-горе (Scanner = PosHelper.GetHardware....)


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


Отговори (1)


Вярвам, че реших проблема си. Тъй като моите призматични модули се зареждат по време на изпълнение в рамките на поддиректория, трябваше да добавя това към 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