Мне приходилось делать это несколько раз, и я исследовал множество различных решений.
Решение, которое я нахожу наиболее элегантным и легким в реализации, может быть реализовано как таковое.
1. Создайте проект, в котором можно создать простой интерфейс.
интерфейс будет содержать подписи всех участников, которым вы хотите позвонить.
public interface IExampleProxy
{
string HelloWorld( string name );
}
Важно, чтобы этот проект был чистым и легким. Это проект, на который AppDomain
могут ссылаться оба, и который позволит нам не ссылаться наAssembly
мы хотим загрузить в отдельный домен из нашей клиентской сборки.
2. Теперь создайте проект с кодом, который вы хотите загрузить отдельно. AppDomain
.
Этот проект, как и клиентский, будет ссылаться на прокси-сервер, и вы реализуете интерфейс.
public interface Example : MarshalByRefObject, IExampleProxy
{
public string HelloWorld( string name )
{
return $"Hello '{ name }'";
}
}
3. Затем в клиентском проекте загрузите код в другой AppDomain
.
Итак, теперь мы создаем новый AppDomain
. Можно указать базовое расположение для ссылок на сборки. Зондирование проверит наличие зависимых сборок в GAC, в текущем каталоге и в AppDomain
базовом местоположении.
// set up domain and create
AppDomainSetup domaininfo = new AppDomainSetup
{
ApplicationBase = System.Environment.CurrentDirectory
};
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
AppDomain exampleDomain = AppDomain.CreateDomain("Example", adevidence, domaininfo);
// assembly ant data names
var assemblyName = "<AssemblyName>, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null|<keyIfSigned>";
var exampleTypeName = "Example";
// Optional - get a reflection only assembly type reference
var @type = Assembly.ReflectionOnlyLoad( assemblyName ).GetType( exampleTypeName );
// create a instance of the `Example` and assign to proxy type variable
IExampleProxy proxy= ( IExampleProxy )exampleDomain.CreateInstanceAndUnwrap( assemblyName, exampleTypeName );
// Optional - if you got a type ref
IExampleProxy proxy= ( IExampleProxy )exampleDomain.CreateInstanceAndUnwrap( @type.Assembly.Name, @type.Name );
// call any members you wish
var stringFromOtherAd = proxy.HelloWorld( "Tommy" );
// unload the `AppDomain`
AppDomain.Unload( exampleDomain );
если вам нужно, существует масса различных способов загрузить сборку. С этим решением вы можете использовать другой способ. Если у вас есть полное имя сборки, мне нравится использовать, CreateInstanceAndUnwrap
поскольку он загружает байты сборки, а затем создает для вас экземпляр вашего типа и возвращает то, object
что вы можете просто преобразовать в свой тип прокси или, если вы этого не сделаете, в строго типизированный код, который вы могли бы используйте среду выполнения динамического языка и назначьте возвращаемый объект dynamic
типизированной переменной, а затем просто вызовите элементы для этого напрямую.
Вот и все.
Это позволяет загрузить сборку, на которую ваш клиентский проект не ссылается, в отдельном AppDomain
и вызывать ее элементы из клиента.
Для тестирования мне нравится использовать окно «Модули» в Visual Studio. Он покажет вам домен вашей клиентской сборки и все модули, загруженные в этом домене, а также ваш новый домен приложения и какие сборки или модули загружены в этом домене.
Главное - убедиться, что код является производным MarshalByRefObject
или сериализуемым.
`MarshalByRefObject позволит вам настроить время жизни домена, в котором он находится. Например, вы хотите, чтобы домен был уничтожен, если прокси не был вызван в течение 20 минут.
Надеюсь, это поможет.