Использование разделяемых сборок

83

Установка сборок со строгими именами в GAC

Предпочитаемым способом для развертывания сборок в GAC в производственной среде является создание инсталляционного пакета Windows MSI (или применение какой-то коммерческой инсталляционной программы, подобной InstallShield), в .NET Framework 4.0 SDK поставляется работающая утилита командной строки gacutil.ехе, которой удобно пользоваться для проведения быстрых тестов.

Для взаимодействия с GAC на своей машине необходимо иметь права администратора, что может требовать внесения соответствующих изменений в параметры контроля учетных записей пользователей (UAC) в Windows Vista или Windows 7.

Ниже перечислены некоторые наиболее важные опции этой утилиты (для вывода полного списка поддерживаемых ею опций служит флаг /?):

Опция Описание
/i Инсталлирует сборку со строгим именем в GAC
/u Удаляет сборку из GAC
/l Отображает список сборок (или конкретную сборку) в GAC

Чтобы инсталлировать сборку со строгим именем с помощью gacutil.exe, нужно открыть в Visual Studio окно командной строки и перейти в каталог, в котором содержится библиотека fontinfo.dll, например:

cd C:\myProject\FontInfo\fontinfo\bin\Debug

Затем можно инсталлировать библиотеку с помощью опции -i:

gacutil -i fontinfo.dll

После этого можно проверить, действительно ли библиотека была развернута, выполнив следующую команду (обратите внимание, что расширение файла при использовании опции /l не указывается):

gacutil -1 fontinfo

Если все в порядке, в окне консоли должен появиться примерно такой вывод (разумеется, значение PublicKeyToken будет уникальным):

Список сборок GAC

Просмотр содержимого GAC с помощью проводника Windows

С выходом версии .NET 4.0 кэш GAC был поделен на две части. В частности, в папке С: \Windows\assembly теперь размещаются библиотеки базовых классов .NET 1.0 — .NET 3.5 (а также различные дополнительные сборки, в том числе библиотеки сторонних производителей). Однако при компиляции сборки в .NET 4.0 и ее развертывания в GAC с помощью gacutil.ехе она размещается в совершенно новом месте, а именно — в папке С:\Windows\Microsoft.NET\assembly\GAC_MSIL.

В этой новой папке также имеется набор подкаталогов, каждый из которых именован в соответствии с дружественным именем конкретной библиотеки кода (например, \System.Windows.Forms,- \System.Core и т.д.). Внутри каждой папки с дружественным именем размещен еще один подкаталог, который всегда именуется по следующей схеме:

v4.0_major.minor.build.revision_publicKeyTokenValue
v4.0_<старший номер>.<младший номер>.<номер сборки>.<номер редакции>_<значение открытого ключа>

Префикс v4.0 свидетельствует о том, что библиотека компилировалась в версии .NET 4.0. После этого префикса идет один символ подчеркивания, а за ним — номер версии изучаемой сборки, каковым в рассматриваемом примере будет 1.0.0.0 для fontinfo.dll. Далее за парой символов подчеркивания следует значение маркера открытого ключа, основанное на строгом имени. На рисунке показано, как может выглядеть структура каталогов fontinfo в среде Windows XP:

Разделяемая сборка со строгим именем

Использование сборки

При создании приложений, использующих разделяемую сборку, единственным отличием от применения приватной сборки является способ, которым должна добавляться ссылка на соответствующую библиотеку в Visual Studio 2010. Фактически для этого используется тот же самый инструмент — диалоговое окно Add Reference. Однако разница в том, что в этом случае упомянутое диалоговое окно не позволяет добавить ссылку на сборку за счет нахождения нужного файла в папке С:\Windows\Assembly, которая предназначена только для сборок .NET 3.5 и предшествующих версий.

Опытные разработчики приложений .NET наверняка помнят, что и раньше при переходе в папку С:\Windows\assembly в диалоговом окне Add Reference внутри Visual Studio не разрешалось добавлять ссылки на разделяемые библиотеки. По этой причине приходилось создавать отдельную копию библиотеки просто для того, чтобы иметь возможность добавлять на нее ссылку. В Visual Studio 2010 дела обстоят гораздо лучше.

Если необходимо добавить ссылку на сборку, которая была развернута в GAC версии .NET 4.0, на вкладке Browse необходимо перейти в представляющий нужную библиотеку каталог по имени v4.0_major.minor.build.revision_publicKeyTokenValue, как показано на рисунке. С учетом этого немного сбивающего с толку факта, давайте создадим новый проект типа Console Application и добавим в него ссылку на сборку fontinfo только что описанным образом. Как и следовало ожидать, после этого в папке References внутри окна Solution Explorer появится соответствующий значок. Выделив этот значок и выбрав в меню View (Вид) пункт Properties (Свойства), в окне Properties можно увидеть, что свойство Copy Local (Локальная копия) теперь установлено в False.

Добавление ссылки на разделяемую сборку

Несмотря на это, добавим в новое клиентское приложение следующий тестовый код:

using System;
using MyFont;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            FontColor fc = new FontColor("Georgia", 14, "Red");
            fc.InfoByFont();

            Console.ReadLine();
        }
    }
}

Если теперь скомпилировать это клиентское приложение и с помощью проводника Windows перейти в каталог, в котором содержится файл Program.exe, то можно будет увидеть, что среда Visual Studio 2010 не скопировала fontinfo.dll в каталог клиентского приложения. Объясняется это тем, что при добавлении ссылки на сборку, в манифесте которой присутствует значение .publickey, Visual Studio 2010 считает, что данная обладающая строгим именем сборка, скорее всего, будет развертываться в GAC, и потому не заботится о копировании ее двоичного файла.

Исследование манифеста SharedCarLibClient

Вспомните, что при генерировании строгого имени для сборки в ее манифест записывается открытый ключ. В связи с этим, когда в клиентское приложение добавляется ссылка на строго именованную сборку, в ее манифест записывается и компактное хеш-значение всего открытого ключа в маркере .publickeytoken. Поэтому, если открыть манифест Program.exe в утилите ildasm.exe, можно увидеть там следующий код (разумеется, значение открытого ключа в маркере .publickeytoken будет выглядеть по-другому):

CIL-код манифеста разделяемой сборки

Если теперь сравнить значение открытого ключа, записанного в манифесте клиента, и отображаемого в GAC, то легко обнаружить, что они совпадают. Как упоминалось ранее, открытый ключ является одной из составляющих идентификационных данных строго именованной сборки. Из-за этого CLR-среда будет загружать только версию 1.0.0.0 сборки по имени fontinfo, из открытого ключа которой может быть получено хеш-значение DC473F9D2D5D12C3. В случае невозможности обнаружить сборку, соответствующую такому описанию в GAC (и приватную сборку по имени fontinfo в каталоге клиента), будет сгенерировано исключение FileNotFoundException.

Лучший чат для C# программистов