Привет,
При попытке загрузить сборку в AppDomain получаю Exception: "Insufficient state to deserialize the object. More information is needed."
Проблема в следующем:
Есть куча DLL (созданных налету через ICodeCompiler->CompileAssemblyFromFile по описанию WebService).
Раньше я загружал их так:
String *sType = String::Format ( S"{0}.{1}", sDynamicNameSpace, sClassName );
Assembly *oAssembly = Assembly::LoadFrom ( sFileNameDll );
Type *tDynamic = oAssembly->GetType ( sType );
Object *oObject = Activator::CreateInstance ( tDynamic );
Object *oResult = tDynamic->InvokeMember ( .............
Сейчас потребовалось переодически эти DLL обновлять, для этого надо грузить их в Domain.
Сделал как в MSDN:
Byte SoapTest::LoadFile ( String *sFileName)[]
{
FileStream *oFileStream = new FileStream ( sFileName, FileMode::Open );
Byte arBuffer[] = new Byte[(int) oFileStream->Length];
oFileStream->Read ( arBuffer, 0, arBuffer->Length );
oFileStream->Close ( );
return arBuffer;
}
..
AppDomainSetup *oAppDomainSetup = new AppDomainSetup ( );
oAppDomainSetup->ApplicationName = sDynamicNameSpace;
oAppDomainSetup->ApplicationBase = sDllPath;
oAppDomainSetup->ShadowCopyFiles = S"true";
Evidence *oEvidence = new Evidence ( AppDomain::CurrentDomain->Evidence );
AppDomain *oAppDomain = AppDomain::CreateDomain ( sDynamicNameSpace, oEvidence, oAppDomainSetup );
oAppDomain->Load ( LoadFile ( sFileNameDll ) );
При этом получаю описанный выше — Exception. В чем может быть проблема ?
PS: CreateInstanceFromAndUnwrap работает, но непонятно как из полученного Proxy получить сам объект, т.к. Type заранее не известен (есть только TypaName)
Object *oObject = oAppDomain->CreateInstanceFromAndUnwrap ( sFileNameDll, sType );
AppDomain.Load пытается провести через ремотинг Assembly, если эта же сборка отсутствует в вызывающем домене, то происходит ошибка сериализации.
Если надо грузить сборки в один домен, а использовать их из другого, то нужен
а) агент — загрузчик — загруженная в основной домен сборка, которая грузится в дочерний через Load(AssemblyName) при этом надо учесть, что если CodeBase дочернего домена иной, нежели у главного, то файл сборки ОБЯЗАН лежать в этой папке или в GAC, так как несмотря на наличие в AssemblyName пути на диске, загрузчик все равно ведет себя одинаково — проверить GAC, проверить приватную директорию, проверить пробинги
б)для ремотинга обязательным условием является присутствие метаданных участвующих во взаимодействии классов у обоих участников взаимодействия, из другого домена нельзя получить удаленный экземпляр класса, если метадщанных нет в вызывающем домене.
Так как грузить сами ваши сборки в основной домен нельзя (вы же их хотите обновлять) значит и ваше приложение и ваши сборки должны иметь ссылки на ОБЩУЮ сборку с основными классами и интерфейсами, которые и будут участвовать во взаимодействии.
Примерный сценарий
То есть например вы грузите в основной домен и в дочерний домен общую сборку, содержащую
а) интерфейс IPlugin
б) сериализуемый класс — дескриптор плагина
б) класс унаследованный от MarshallByRef типа PluginEnumerator, который возвращает список всех классов, поддерживающих IPlugin и обнаруженных в своем домене
г) класс — загрузчик плагина, инстанцирующий плагин и передающий ссылку на IPlugin, скажем PluginLoader
потом в домен грузятся ваши сборки, классы в которых реализуют интерфейс IPlugin
Так, теперь есть два домена, с общей сборкий и некими неизвестными и глубоко отделенными от основного домена сборками внутри дочернего. Задача — инстанцировать некий Plugin1, про который основной домен ровным счетом ничего не знает.
Для этого основной домен делает:
1) создает через активатор экземпляр PluginEnumerator (так как он MarshallByRef, то его исполнение будет происходить в дочернем домене)
2) получаем у енумератора список всех плагинов в дочернем домене, возвращенных в виде массива дескрипторов плагинов (в самом простом виде это просто список каких-то ключей или просто количество плагинов для доступа по номеру)
3) если понадобился удаленный экземпляр нужного IPlugin, мы опять же в дочернем домене создаем экземпляр PluginLoader (так же MarshallByRef) и в качестве параметра передаем полученный на 2-м этапе дескриптор. PluginLoadder загружает конкретный класс и передает обратно ссылку на его интерфейс IPlugin, естественно что полученный Proxy вам уже не удастся к чему-то еще привести, так как в основном домене есть только метаданные об IPlugin и именно этот интерфейс маршалится через ремотинг
Таким образом мы получаем что хотели. Главное запомнить одно, что-то общее у доменов быть должно для взаимодействия, просто так лазить в соседний домен и грузить из него классы концептуально нельзя.
данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение