Speak.Me Учить иностранные слова

C#: домены приложений (Application Domains)

Домен приложения — это своеобразный контейнер, внутри которого запускается программа, и который изолирует ее во время выполнения. Домен задает границы управляемой памяти для приложения и является контейнером для загруженных сборок и параметров конфигурации приложения. Каждый процесс обычно размещает только один домен приложения — стандартный домен, автоматически созданный CLR при запуске процесса. Однако в рамках одного процесса возможно создавать дополнительные домены приложений.

Несколько доменов приложений обычно применяются с целью обеспечения изоляции схожей с процессами, но с меньшими накладными расходами. Когда дополнительные домены приложения созданы внутри одного и того же процесса, среда CLR обеспечивает для каждого из них уровень изоляции, сходный с таковым в случае выполнения в отдельных процессах. Каждый домен имеет отдельную память, объекты в одном домене не могут конфликтовать с объектами в другом домене, статические члены одного и того же класса в каждом домене имеют независимые значения. Например в ASP.NET для каждого сайта создается отдельный домен приложения, позволяя сайтам выполняться в одном процессе не влияя друг на друга.

Еще одна причина создания отдельного домена приложения — позволить сборкам выгружаться не завершая процесс. После загрузки сборки файл сборки блокируется и его нельзя редактировать или заменить. Чтобы разблокировать файл, сборку надо выгрузить. Единственный способ выгрузить сборку — закрыть домен приложения, в котором она загружена. Это становится проблематично если сборка была загружена в стандартный домен приложения, так как закрытие этого домена означает закрытие приложения. Загрузка сборки в отдельный домен приложения, который может быть уничтожен, позволяет обойти данную проблему.

Создание и уничтожение доменов приложений

Дополнительные домены приложений в процессе создаются и уничтожаются с помощью статических методов AppDomain.CreateDomain и AppDomain.Unload:

При выгрузке стандартного домена приложения (созданного CLR при запуске приложения) все другие домены приложений выгружаются автоматически и приложение закрывается. Выяснить является ли домен стандартным можно с помощью свойства IsDefaultDomain объекта AppDomain.

Класс AppDomainSetup позволяет задать опции для нового домена. Его основные свойства:

Свойство ApplicationBase задает базовый каталог домена приложения, используемый в качестве корня для автоматического поиска сборок. Свойство PrivateBinPath — это разделенный точками с запятой список подкаталогов ниже базового каталога, в которых CLR должна искать сборки. Задать эти свойства можно только перед запуском домена приложения. Свойство PrivateBinPath всегда является относительным и находится ниже базовой папки домена приложения. Задавать абсолютные пути нельзя.

Если свойству PrivateBinPathProbe задать значение отличное от пустой строки, то базовый каталог из пути поиска сборок будет исключен.

Новый домен можно подписать на получение событий разрешения сборок, определенных в домене инициаторе:

Обработчиком событий может быть только статический метод, который будет доступен в обоих доменах. Запускаться обработчик будет в новом домене несмотря на то, что определен в основном.

Непосредственно перед выгрузкой домена приложения, отличного от стандартного, генерируется событие DomainUnload. Событие можно использовать для выполнения очистки. Домен приложения будет выгружен только после завершения выполнения всех обработчиков.

Непосредственно перед закрытием самого приложения генерируется событие ProcessExit на всех загруженных доменах, включая стандартный. Выполнения обработчиков этого события нормируется по времени: две секунды на домен и три секунды в общем.

Метод DoCallBack

Класс AppDomain содержит метод DoCallBack, позволяющий выполнить статический метод в другом домене. При этом сборка, содержащая выполняемый метод, автоматически загрузится в новый домен. В следующем примере метод текущего выполняемого класса запускается в новом домене:

Обмен данными между доменами

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

С помощью метода CreateInstanceAndUnwrap класса AppDomain можно создавать экземпляры типов в другом домене. При этом тип, экземпляр которого создается в другом домене должен быть унаследован от класса MarshalByRefObject.

Метод CreateInstanceAndUnwrap возвращает прозрачный прокси, который фактически не является прямой ссылкой на объект в другом домене, но ведет себя так, как если бы он ею являлся.

Метод CreateInstanceAndUnwrap принимает имена сборки и типа в виде строки.

Метод CreateInstanceFromAndUnwrap аналогичен методу CreateInstanceAndUnwrap, но вместо имени сборки принимает имя файла сборки или полный путь к нему.