Я не использовал MEF (потому что реализовать его функциональность с нуля так же легко, в отличие от MAF), но у меня есть некоторый опыт работы с голыми доменами приложений.
Трудно сказать многое, не видя ваш код, но из того, что вы написали, мне кажется, что вы путаете некоторые вещи.
Как вы, наверное, знаете, и вы уже указали, вы не можете обновить уже загруженную сборку. Загрузка другой версии (с другой подписью) означает, что у вас загружены две разные сборки. Типы внутри них будут иметь разные строгие имена. На самом деле вы можете справиться с этим, если хотите. Единственный способ выгрузить сборку - выгрузить домен приложения, в котором она находится.
Моя проблема с этим предложением:
... загрузить плагин, содержащий ApiController, в отдельном домене приложения
и используйте MarshalByRefObject для загрузки из основного домена приложения
Определение типа (класса) + данные кода и экземпляра - две разные вещи. Загрузка сборки в домен приложения означает, что вы загружаете определение типа и код. Сериализация появляется, когда вы хотите перенести данные экземпляра через границы домена приложения. Вы не можете загрузить определение типа и код из другого домена приложения, как вы написали (на самом деле вы могли бы, но я сомневаюсь, что вам нужно). Чтобы иметь возможность передавать данные экземпляра, обе стороны должны знать об определении типа передаваемого экземпляра. Сериализация и передача в этом случае управляются средой удаленного взаимодействия .net.
У вас есть два варианта: либо переместить все данные экземпляра и сериализовать их все время, либо вы выбираете способ MarshalByObjRef
, как вы и сказали. Давай останемся с этим. Чтобы иметь возможность работать с экземпляром в другом домене приложения, вам нужно будет создать экземпляр типа в другом домене приложения, используя активатор (в этом случае вы не можете использовать оператор new
), и получить ссылку на него, которая будет прокси на основе типа, который вы знаете (это может быть интерфейс или базовый класс, а не только точный тип). Отражение несколько ограничено в такой ситуации, еще меньше подготовлен asp.net, чтобы выяснить методы удаленного объекта - но вы могли бы помочь ему с правильными интерфейсами.
Итак, давайте представим, что вы создали экземпляр контроллера в другом домене приложения, и у вас есть ссылка удаленного взаимодействия, назначаемая типу интерфейса, который определяет все методы, которые вы должны предоставить asp.net. Теперь появится возможность сериализации, когда вы пытаетесь получить доступ к членам класса контроллера. Каждый параметр метода и тип возвращаемого метода должны быть сериализуемыми. Но не сам класс, поскольку он является MashalByObjRef
потомком и не будет рассматриваться как пример. И MashalByObjRef
не имеет ничего общего с тем, как вы загружаете сборку в домен приложения.
Но подождите! И MarshalByObjRef
, и ApiController
являются абстрактными классами. Как вы хотите получить свой фактический класс контроллера из обоих? Ты не можешь Поэтому я не думаю, что вы можете напрямую использовать apicontrollers из другого домена приложения.
Я мог представить две вещи:
1) Загрузите новую подписанную версию в ту же сборку и настройте механизм маршрутизации для перенаправления запросов на последнюю версию (возможно, она еще не действительна, но может быть хорошей отправной точкой: https://www.strathweb.com/2013/08/customizing-controller-discovery-in-asp-net-web-api/).
Конечно, при перезапуске вы должны загрузить только самую последнюю версию, если вам не нужно иметь несколько версий параллельно.
2) Сделать слегка сложную инфраструктуру:
- определить интерфейс для логики контроллера
- создает apicontroller без версий и без логики, но способный создавать и выгружать домены приложений, загружать сборки в них, сохранять ссылки на экземпляры, реализующие интерфейс, созданный в них выше, и направлять запросы к этим
- Имейте в виду, что вы не сможете передать некоторые вещи (например, контекст контроллера) в логику в другом домене приложения, вам придется извлечь то, что вам нужно, или воссоздать на другой стороне
- таким образом, вы можете иметь логический
MarshalByObjRef
потомок в «удаленном» домене приложения и ваш контроллер ApiController
потомок в главном домене приложения.
- Я бы создал промежуточный абстрактный класс, расширяющий
ApiController
с возможностью обрабатывать вышеуказанное разделение самостоятельно. Остальная часть приложения не будет знать об этом.
- Помните о пожизненных сервисах, связанных с удаленным взаимодействием, которые вы можете обрабатывать, используя спонсора или переопределяя некоторые методы MarshalByObjRef.
Не простой подход, вы столкнетесь с некоторыми дополнительными проблемами ...