Делаем отгружаемые сборки: взаимодействуем между доменами без маршаллинга

сегодня в 16:47

Для начала, полный список выложенных на Хабре статей данного цикла

Ссылка на проект в GitHub: 97938edf1170406c842b0613d0c84ae9.png DotNetEx

На множественных ресурсах время от времени задается вопрос. Можно ли сделать отгружаемые сборки с текущего домена? Так, чтобы попользовался и «давай, до свидания!»? Везде и всегда ответ, который давался — это «нет». Ведь единственное, что можно выгрузить — это домен. Соответственно, если хочется наладить отгрузку, сборку надо помещать в домен, и налаживать между доменами взаимодействие через сериализуемые типы. А это — очень медленное взаимодействие. А мы скажем так. Можно. С ньюансами. Загружать мы будем также в отдельный домен. Но отменим сериализацию при вызове методов между доменами.

Вопросы, которые мы будем решать:

Создание домена с возможностью отдачи объекта из домена в родительский Выгрузка сборки Решение проблемы Итак, как всегда, будем решать проблемы по мере появления: Как мы уже выяснили в прошлых статьях, память общая и не зависит от доменов. А это значит, что если найти способ передачи указателя на объект, то можно научиться без сериализации передавать объекты между доменами.Возьмем некий общий тип. Для упрощения, возьмем тип из mscorlib: IServiceProvider.Создадим сборку, которую мы собираемся подружить с возможностью отгрузки:

public class Implementation: IServiceProvider { public override string ToString () { return «Awesome»; }

public object GetService (Type serviceType) { return new object (); } } Теперь напишем класс, который будет создавать домен и уметь создавать в этом домене экземпляры классов: public class AppDomainRunner: MarshalByRefObject, IDisposable { private AppDomain appDomain; private Assembly assembly; private AppDomainRunner remoteRunner;

private void LoadAssembly (string assemblyPath) { assembly = Assembly.LoadFile (assemblyPath); }

public AppDomainRunner (string assemblyPath) { // make appdomain appDomain = AppDomain.CreateDomain («PseudoIsolated», null, new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory });

// create object instance remoteRunner = (AppDomainRunner)appDomain.CreateInstanceAndUnwrap (typeof (AppDomainRunner).Assembly.FullName, typeof (AppDomainRunner).FullName); remoteRunner.LoadAssembly (assemblyPath); }

public IntPtr CreateInstance (string typename) { return remoteRunner.CreateInstanceImpl (typename); }

private IntPtr CreateInstanceImpl (string typename) { return EntityPtr.ToPointer (assembly.CreateInstance (typename)); }

public void Dispose () { assembly = null; remoteRunner = null; AppDomain.Unload (appDomain); }

Теперь напишем класс для IoC rконтейнера: public class Container: IDisposable { private AppDomainRunner appdomain;

private Dictionary instances = new Dictionary();

public Container (string assemblyName) { appdomain = new AppDomainRunner (Path.Combine (System.Environment.CurrentDirectory, assemblyName)); }

public void Register(string fullTypeName) { instances.Add (typeof (TInterface), EntityPtr.ToInstance(appdomain.CreateInstance (fullTypeName))); }

public TInterface Resolve() { return (TInterface)(instances[typeof (TInterface)]); }

public void Dispose () { appdomain.Dispose (); } } И последнее — использующий код: static void Main (string[] args) { using (var container = new Container («library.dll»)) { container.Register(«IocLibrary.Implementation»); var serviceProvider = container.Resolve();

Console.WriteLine («calling method without proxy: {0}», serviceProvider); Console.WriteLine («Current domain assemblies: {0}», string.Join (»,», AppDomain.CurrentDomain.GetAssemblies ().Select (asm => asm.GetName ().Name).ToArray ())); } } Выводы Как говорится, сделать отгружаемые типы нельзя, но если хочется, то можно. Необходимо просто как-то передать между доменами указатель на объект и им можно будет на равных правах пользоваться.Минус способа только один: мы не имеем права использовать объекты после выгрузки сборки. Это минус по одной простой причине: надо дополнительно контролировать порядок отгрузки и потери ссылки на объекты. Но, в общем случае это не проблема =)

1283

27

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

© Habrahabr.ru