Самая популярная архитектура для персональных компьютеров в мире

Домен приложения .NET - создание и использование доменов

Домен приложения - играет роль процесса в среде .NET. Домен приложения .NET позволяет работать нескольким программам в рамках одного процесса операционной системы, не мешая друг другу. В каждом процессе ОС может быть несколько доменов. По-умолчанию, при старте процесса создается один домен. Домены не могут использовать объекты друг друга напрямую.

Домен приложения

Создание домена приложения

Для создания нового домена достаточно вызвать статический метод AppDomain.CreateDomain(...). У этого метода обязательный параметр только один: дружественное имя нового домена приложений. Это имя только для отображения в системных утилитах и оно не обязательно должно быть уникально. Этот метод возвратит объект класса AppDomain, в который уже можно загружать сборки и запускать методы их классов.

Выгрузка домена приложения

Выгрузка домена аналогична завершению процесса операционной системы. Для выгрузки домена служит статический метод AppDomain.Unload(...). В качестве единственного параметра этот метод принимает объект домена, который нужно выгрузить из памяти.

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

Границы доменов в первую очередь распространяются на оперативную память. Поэтому нельзя использовать объекты одного домена из другого напрямую. Для взаимодействия между доменами можно использовать классические методики: сеть/сокеты, файлы, каналы и др. Но если взаимодействовать должны два .NET домена, то удобнее всего воспользоваться встроенной функцией .NET, созданной специально для этого. Чтобы объект домена A можно было создать из домена B нужно класса объекта A унаследовать от класса MarshalByRefObject. Если этого не сделать то получится исключение Type '...' in assembly '...' is not marked as serializable.. Далее в домене B нужно создать новый домен. И после этого можно создавать объекты домена A из домена B с помощью метода domain.CreateInstanceAndUnwrap("имя_сборки", "namespace...имя_класса"). Этот метод возвращает объект прокси, а не сам объект домена A. Можно преобразовать этот прокси к своему классу домена приложений A. Но если используемая сборка не подключена в домену B, то можно использовать тип dynamic и вызывать методы созданного объекта. Код методов созданного объекта будет выполняться в домене A.

Зачем нужны домены приложений

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

Пример

Дочерний домен

Для примера нужно создать сборку ChildDomain типа ClassLibrary.

	
// ChildDomain.dll
using System;

namespace ChildDomain
{
	// Обязательно наследуемся от MarshalByRefObject
    public class ClassOfChildDomain: MarshalByRefObject
    {
        public string GetTestString()
        {
            return "Hello";
        }
    }
}	
	
	

Стартовый домен

Код приложения, которое создает новый домен и загружает в него сборку ChildDomain, приведен ниже:

	
// MainDomain.exe
using System;
using System.Runtime.Remoting;

namespace MainDomain
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain domain = AppDomain.CreateDomain("new domain");
			
	// создание прокси
	// помещаем в ссылку на динамический объект
            dynamic proxyOfChildDomainObject = 
                domain.CreateInstanceAndUnwrap("ChildDomain", 
				"ChildDomain.ClassOfChildDomain");
			
	// Параметры будут сериализованы и вызов будет отправлен в домен ChildDomain
            string str = proxyOfChildDomainObject.GetTestString(); // Вернет Hello
            
	// выгрузка домена
			AppDomain.Unload(domain);
        }
    }
}	
	
Конечно, нужно не забыть положить ChildDomain.dll рядом с MainDomain.exe.

Частые исключения из разряда ЗАБЫЛ

Type 'ChildDomain.ClassOfChildDomain' in assembly 'ChildDomain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

Забыли унаследоваться от MarshalByRefObject.

Could not load file or assembly 'ChildDomain' or one of its dependencies. Не удается найти указанный файл.

Забыли положить файл ChildDomain.dll рядом с MainDomain.exe. Можно добавить Reference в MainDomain на ChildDomain и тогда студия сделать эту работу за вас.

'System.MarshalByRefObject' does not contain a definition for 'GetTestString'

Это исключение возникает, если не сделать класс ClassOfChildDomain публичным.

'ChildDomain.ClassOfChildDomain.GetTestString()' is inaccessible due to its protection level

Здесь мы забыли сделать метод публичным.

Could not load type 'ChildDomain.ClassOfChildDomain' from assembly 'ChildDomain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Забыли сделать класс ClassOfChildDomain ;).

Текущий домен приложения

Текущий домен приложения хранится в статическом свойстве AppDomain.CurrentDomain.

Copyright (c) 2014, cpubook.ru
Архитектура x86