Мне приходилось делать это несколько раз, и я искал много разных решений.
Решение, которое я считаю наиболее элегантным и простым в реализации, может быть реализовано как таковое.
1. Создайте проект, который вы можете создать простой интерфейс
интерфейс будет содержать подписи любых пользователей, которым вы хотите позвонить.
public interface IExampleProxy
{
string HelloWorld( string name );
}
Важно, чтобы этот проект был чистым и легким. Это проект, на который могут ссылаться оба AppDomain
и который позволит нам не ссылаться на Assembly
, который мы хотим загрузить в отдельный домен из нашей клиентской сборки.
2. Теперь создайте проект с кодом, который вы хотите загрузить в отдельном AppDomain
.
Этот проект, как и клиентский proj, будет ссылаться на proxy proj, и вы реализуете интерфейс.
public interface Example : MarshalByRefObject, IExampleProxy
{
public string HelloWorld( string name )
{
return $"Hello '{ name }'";
}
}
3. Далее в клиентском проекте загружаем код в другой AppDomain
.
Итак, теперь мы создаем новый AppDomain
. Можно указать базовое местоположение для сборочных ссылок. Зондирование проверит наличие зависимых сборок в GAC и в текущем каталоге, а также AppDomain
base loc.
// 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 минут.
Надеюсь, это поможет.