Приватные сборки
72C# --- Сборки .NET --- Приватные сборки
Приватные сборки должны всегда размещаться в том же каталоге, что и клиентское приложение, в котором они используются (т.е. в каталоге приложения), или в каком-то из его подкаталогов.
Благодаря этому, при возникновении в какой-то из этих клиентских программ необходимости в использовании типов, определенных во внешней сборке, CLR-среда будет просто загружать локальную копию этой сборки. Отсутствие у исполняющей среды .NET потребности заглядывать в системный реестр при поиске внешних сборок позволяет перемещать библиотеку в любое другое место на машине и все равно успешно запускать эти приложения (такой процесс часто называют развертыванием с помощью Хсору).
Удаление (или репликация) приложения, в котором используются приватные сборки, тоже не требует особых усилий: достаточно просто удалить (или скопировать) папку приложения. В отличие от СОМ-приложений, беспокоиться о десятках остающихся настроек в системном реестре совершенно не нужно. Более того, удаление приватных сборок не может нарушить работу каких-то других приложений на машине.
Идентификационные данные приватной сборки
Идентификационные данные приватной сборки включают дружественное имя и номер версии, которые фиксируются в манифесте сборки. Дружественным называется имя модуля, в котором содержится манифест сборки, без файлового расширения.
По причине изолированной природы приватной сборки CLR-среда, вполне логично, не использует номер версии при выяснении места ее размещения. Она предполагает, что приватные сборки не нуждаются в выполнении сложной проверки версии, поскольку клиентское приложение является единственной сущностью, которой "известно" об их существовании. Из-за этого на одной машине может размещаться множество копий одной и той же сборки в различных каталогах приложений.
Процесс зондирования
Исполняющая среда .NET определяет местонахождение приватной сборки с применением так называемой технологии зондирования, которая в действительности является менее докучливой, чем может показаться из-за ее названия. В ходе процесса зондирования производится отображение запроса внешней сборки на место размещения соответствующего двоичного файла. Запрос внешней сборки, собственно говоря, может быть явным или неявным. Неявный запрос происходит тогда, когда CLR-среда заглядывает в манифест для определения, где находится требуемая сборка, по маркерам .assembly extern.
Явный запрос осуществляется программно за счет применения метода Load() или LoadFrom() (оба являются членами класса System.Reflection.Assembly) и обычно предназначен для выполнения позднего связывания или динамического вызова членов интересующего типа:
// Явный запрос на выполнение загрузки, основанный
// на использовании дружественного имени.
Assembly asm = Assembly.Load("CarLibrary");
В обоих случаях CLR-среда извлекает дружественное имя сборки и начинает зондировать каталог клиентского приложения в поисках интересующего файла (например, файла по имени CarLibrary.dll). Если ей не удается обнаружить такой файл, она предпринимает попытку найти исполняемую сборку с таким же дружественным именем (т.е., например, CarLibrary.exe). Если ей не удается найти ни одного из упомянутых файлов в каталоге приложения, она генерирует во время выполнения исключение FileNotFoundException.
Конфигурирование приватных сборок
Хотя допускается развертывания .NET-приложения просто за счет копирования всех требуемых сборок в одну папку на жестком диске пользователя, скорее всего, понадобится определить несколько отдельных подкаталогов для группирования взаимосвязанного содержимого.
Давайте более подробно рассмотрим конфигурирование приватных сборок. Создадим два файла: font.cs который скомпилируем в исполняющую программу и fontinfo.cs, в котором будут содержаться библиотеки классов:
// Файл fontinfo.cs
using System;
namespace MyFont
{
public class BaseFont
{
public string Name;
public int FontSize;
public BaseFont(string Name, int FontSize)
{
this.Name = Name;
this.FontSize = FontSize;
}
public virtual void InfoByFont()
{
Console.WriteLine("Информация о шрифте: \n" +
"Тип: " + Name + "\nРазмер: "+FontSize + "px");
}
}
public class FontColor : BaseFont
{
public string Color;
public FontColor(string Name, int FontSize, string Color)
: base(Name, FontSize)
{
this.Color = Color;
}
public override void InfoByFont()
{
Console.WriteLine("Информация о шрифте: \n" +
"Тип: " + Name + "\nРазмер: " + FontSize + "px\n"
+ "Цвет: " + Color);
}
}
}
// Файл font.cs
using System;
using MyFont;
namespace FontInfo
{
class Program
{
static void Main()
{
FontColor obj = new FontColor("Arial", 12, "Green");
obj.InfoByFont();
Console.ReadLine();
}
}
}
После компиляции, каталог проекта будет следующего вида:
В данном случае проект будет работать как и ожидалось, но что, если возникнет потребность разместить dll-файл в отдельной папке? В этом случае CLR-среде не удается обнаружить сборку fontinfo непосредственно в каталоге приложения и потому она сгенерирует исключение FileNotFoundException.
Чтобы указать CLR-среде, что следует зондировать подкаталог создадим новый конфигурационный файл по имени font.ехе.config с помощью любого текстового редактора и сохраним его в той же папке, в которой содержится само приложение font.ехе. Откроем этот файл и введем в него следующий код (обратите внимание, что язык XML чувствителен к регистру символов):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="info"></probing>
</assemblyBinding>
</runtime>
</configuration>
Здесь info показывает имя папки, в которую помещен dll-файл. Файлы *.config в .NET всегда начинаются с корневого элемента <configuration> Вложенный в него элемент <runtime> может содержать элемент <assemblyBinding>, а тот, в свою очередь — вложенный элемент <probing>. В данном примере главный интерес представляет атрибут privatePath, поскольку именно он служит для указания подкаталогов внутри каталога приложения, которые должна зондировать CLR.
Теперь, когда конфигурационный файл font.ехе.config готов, давайте снова попробуем запустить клиентское приложение. На этот раз выполнение font.ехе должно пройти без проблем (если это не так, вернитесь и проверьте конфигурационный файл еще раз на предмет опечаток).
Обратите особое внимание, что то, какая именно сборка размещается в каждом подкаталоге, в элементе <probing> не указывается. Другими словами, утверждать, что в подкаталоге info размещена сборка fontinfo.dll, а в подкаталоге OtherFont — сборка FontStyle нельзя. Элемент <probing> просто указывает CLR-среде искать запрашиваемую сборку во всех перечисленных подкаталогах до тех пор, пока не будет найдено первое совпадение.
Очень важно иметь в виду, что атрибут privatePath не допускается применять для указания ни абсолютного (С:\Папка\Подпапка), ни относительного (..\\ОднаПапка\\ДругаяПапка) пути. Чтобы указать каталог, находящийся за пределами каталога клиентского приложения, необходимо использовать совершенно другой XML-элемент — <codeBase>.
В атрибуте privatePath можно указывать несколько подкаталогов в виде разделенного точками с запятой списка. В данном случае этого делать не требуется, но ниже приведен пример, в котором CLR-среде указывается просматривать клиентские подкаталоги info и info\fontstyle:
<probing privatePath="info; info\fontstyle"/>
Изменим для целей тестирования имя конфигурационного файла и попробуем запустить приложение снова. На этот раз выполнение клиентского приложения должно завершиться неудачей. Вспомните, что имя файла *.config должно включать в качестве префикса имя соответствующего клиентского приложения. И, наконец, давайте попробуем открыть конфигурационный файл для редактирования и заменить символы любого XML-элемента на прописные. В этом случае запуск клиентского приложения должен завершиться неудачей (язык XML чувствителен к регистру символов).