ГЛАВА 3
Совместно используемые
сборки и сборки
со строгим именем
В главе 2 мы говорили о компоновке, упаковке и развертывании сборки. При этом
основное внимание уделялось закрытому развертыванию (private deployment),
когда сборки, предназначенные исключительно для одного приложения, помещают
в базовый каталог приложения или в его подкаталог. Закрытое развертывание
сборок дает компаниям большие возможности для управления именованием, вер"
сиями и особенностями работы сборок.
В этой главе я сосредоточусь на создании сборок, которые могут совместно
использоваться несколькими приложениями. Замечательный пример глобально
развертываемых сборок — это сборки, поставляемые вместе с Microsoft .NET Frame"
work, поскольку почти все управляемые приложения используют типы, опреде"
ленные Microsoft в библиотеке классов .NET Framework Class Library (FCL).
Как сказано в главе 2, Windows получила репутацию нестабильной ОС глав"
ным образом из"за того, что для создания и тестирования приложений приходится
использовать чужой код. В конце концов любое приложение для Windows, кото"
рое вы пишете, вызывает код, созданный разработчиками Microsoft. Более того,
самые разные компании производят элементы управления, которые разработчи"
ки затем встраивают в свои приложения. Фактически такой подход стимулирует
сама платформа .NET Framework, а со временем, вероятно, число производителей
элементов управления возрастет.
Время не стоит на месте, как и разработчики из Microsoft и сторонние произ"
водители элементов управления: они устраняют ошибки, добавляют в свой код но"
вые возможности и т. п. В конечном счете на жесткий диск пользовательского ком"
пьютера попадает новый код. Ранее установленное и до сих пор прекрасно рабо"
тавшее пользовательское приложение теперь уже не использует тот код, с которым
оно создавалось и тестировалось. В итоге поведение такого приложения становит"
ся непредсказуемым, что в свою очередь расшатывает стабильность Windows.
Решить проблему управления версиями файлов чрезвычайно трудно. На самом
деле я готов спорить, что если взять любой файл и изменить в нем значение одно"
го"единственного бита с 0 на 1 или наоборот, то никто не сможет гарантировать,
что программы, использовавшие исходную версию этого файла, будут работать сГЛАВА 3 Совместно используемые сборки и сборки со строгим именем 63
новой версией файла как ни в чем не бывало. Это утверждение верно хотя бы по"
тому, что множество программ случайно или преднамеренно использует ошибки в
других программах. Если в более поздней версии кода будет исправлена какая"либо
ошибка, то использующее ее приложение станет работать непредсказуемо.
Итак, вопрос в следующем: как, устраняя ошибки и добавляя к программам новые
функции, в то же время гарантировать, что изменения не нарушат работу других
приложений? Я долго думал над этим и пришел к выводу: это просто невозмож"
но. Но, очевидно, такой ответ не устроит никого, поскольку в поставляемых фай"
лах всегда будут ошибки, а разработчики всегда будут одержимы желанием добав"
лять новые функции. Должен все же быть способ распространения новых фай"
лов, который позволит надеяться, что все приложения при этом будут работать
замечательно, а если это окажется не так, легко вернуть приложение в последнее
состояние, в котором оно прекрасно работало.
В этой главе я расскажу об инфраструктуре .NET Framework, призванной ре"
шить проблемы управления версиями. Позвольте сразу предупредить: речь пой"
дет о сложных материях. Нам придется рассмотреть массу алгоритмов, правил и
политик, встроенных в общеязыковую исполняющую среду (CLR). Помимо этого,
будут упомянуты многие инструменты и утилиты, которыми приходится пользо"
ваться разработчику. Все это представляет собой определенную сложность, посколь"
ку, как я уже сказал, проблема управления версиями непроста сама по себе, то же
можно сказать и о подходах к ее решению.
Примечание Мне часто приходится консультировать людей из Micro"
soft, в частности пришлось много поработать с командой, работающей
над архитектурой управления версиями. Эта команда отвечает за совер"
шенствование управления версиями в CLR. Эти парни планируют изме"
нить будущие версии CLR, чтобы управление версиями стало намного
проще. К сожалению, эти изменения не попали в CLR версии 2.0 — они
отложены до следующих версий. Материал этой главы по большей час"
ти не утратит актуальности и после этих изменений — просто некото"
рые процессы упростятся.
Два вида сборок — два вида развертывания
.NET Framework поддерживает два вида сборок: с нестрогими именами (weakly
named assemblies) и со строгими именами (strongly named assemblies).
Внимание! Вы не найдете термин «сборка с нестрогим именем» в до"
кументации по .NET Framework. Почему? А потому, что я сам его приду"
мал. В действительности в документации нет термина для обозначения
сборки, у которой отсутствует строгое имя. Поэтому я решил обозначить
такие сборки специальным термином, чтобы потом можно было недву"
смысленно указать, о каких сборках идет речь.
Сборки со строгими и нестрогими именами идентичны по структуре, то есть
в них используется один файловый формат — portable executable (PE) и они со"
стоят из заголовка PE32(+), CLR"заголовка, метаданных, таблиц декларации, а также64 Часть I Основы CLR
IL"кода, который мы рассмотрели в главах 1 и 2. Оба типа сборок компонуются
при помощи одних и тех же инструментов, например компилятора C# или AL.exe.
В действительности сборки со строгими и нестрогими именами отличаются тем,
что первые подписаны при помощи пары ключей, уникально идентифицирующей
издателя сборки. Эта пара ключей позволяет уникально идентифицировать сбор"
ку, обеспечивать ее безопасность, управлять ее версиями, а также развертывать в
любом месте пользовательского жесткого диска или даже в Интернете. Возмож"
ность уникально идентифицировать сборку позволяет CLR при попытке привяз"
ки приложения к сборке со строгим именем применить определенные политики,
которые гарантируют безопасность. Эта глава посвящена разъяснению сущности
сборок со строгим именем и политик, применяемых к ним CLR.
Развертывание сборки может быть закрытым или глобальным. Сборку первого типа
развертывают в базовом каталоге приложения или в одном из его подкаталогов. Для
сборки с нестрогим именем возможно лишь закрытое развертывание. О сборках с
закрытым развертыванием речь шла в главе 2. Сборку с глобальным развертывани"
ем устанавливают в каком"либо общеизвестном каталоге, который CLR проверяет при
поиске сборок. Такие сборки можно развертывать как закрыто, так и глобально.
В этой главе я объясню, как создают и развертывают сборки со строгим именем. Све"
дения о типах сборок и способах их развертывания суммированы в табл. 3"1.
Табл. 3-1. Возможные способы развертывания сборок со строгими
и нестрогими именами
Тип сборки Закрытое развертывание Глобальное развертывание
Сборка с нестрогим именем Да Нет
Сборка со строгим именем Да Да
Примечание Настоятельно рекомендую назначать сборкам строгие име"
на. Вполне вероятно, что будущие версии CLR потребуют, чтобы все сбор"
ки получали строгие имена, а сборки с нестрогими именами будут по"
ставлены вне закона. Проблема с нестрогими сборками в том, что мож"
но создать несколько разных сборок с одним нестрогим именем. С дру"
гой стороны, присвоение строгого имени позволяет уникально иденти"
фицировать ее. Если среда CLR сможет уникально идентифицировать
сборку, она будет в состоянии применить больше политик, связанных с
управлением версиями и обратной совместимостью. По большому сче"
ту, устранение возможности создавать сборки с нестрогими именами
упрощает понимание политик управления версиями в CLR.
Назначение сборке строгого имени
Если планируется предоставить доступ к сборке нескольким приложениям, ее
следует поместить в общеизвестный каталог, который CLR должна автоматичес"
ки проверять, обнаружив ссылку на сборку. Однако с этим связана проблема —
что, если две (или больше) компаний сделают сборки с одинаковыми именами?
В таком случае, если обе эти сборки будут скопированы в один общеизвестный
каталог, «победит» последняя из них, а работа приложений, использовавших пер"ГЛАВА 3 Совместно используемые сборки и сборки со строгим именем 65
вую, нарушится — ведь первая была затерта второй при копировании (это и ста"
ло причиной «ада DLL» в современных Windows"системах — все DLL"библиотеки
копировались в папку System32).
Очевидно, одного имени файла мало, чтобы различать две сборки. CLR долж"
на поддерживать некий механизм, позволяющий уникально идентифицировать
сборку. Именно для этого и служат «строгие имена». У сборки со строгим именем
четыре атрибута, уникально ее идентифицирующих: имя файла (без расширения),
номер версии, идентификатор регионального стандарта и открытый ключ. Посколь"
ку открытые ключи представляют собой очень большие числа, вместо последне"
го атрибута используется небольшой хеш открытого ключа, который называют
маркером открытого ключа (public key token). Следующие четыре строки (иногда
их называют «отображаемым именем сборки» — assembly display name) иденти"
фицируют совершенно разные файлы сборки:
"MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
"MyTypes, Version=1.0.8123.0, Culture="enUS", PublicKeyToken=b77a5c561934e089"
"MyTypes, Version=2.0.1234.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
"MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Первая строка идентифицирует файл сборки MyTypes.exe или MyTypes.dll (на
самом деле, по строке идентификации нельзя узнать расширение файла сборки).
Компания"производитель назначила сборке номер версии 1.0.8123.0; в ней нет ком"
понентов, зависимых от региональных стандартов, так как атрибут Culture опреде"
лен как neutral. Но сделать сборку MyTypes.dll (или MyTypes.exe) с номером версии
1.0.8123.0 и нейтральными региональными стандартами может любая компания.
Должен быть способ отличить сборку, созданную этой компанией, от сборок
других компаний, которым случайно были назначены те же атрибуты. В силу ряда
причин Microsoft предпочла другим способам идентификации (при помощи GUID,
URL и URN) использование стандартных криптографических технологий, осно"
ванных на паре из закрытого и открытого ключей. В частности, криптографические
технологии позволяют проверять целостность данных сборки при установке ее
на жесткий диск, а также обеспечивают предоставление прав доступа для сборки
в зависимости от ее издателя. Все эти методики мы обсудим ниже.
Итак, компания, желающая снабдить свои сборки уникальной меткой, должна
получить пару ключей — открытый и закрытый, после чего открытый ключ мож"
но будет связать со сборкой. У всех компаний будут разные пары ключей, поэто"
му они могут создавать сборки с одинаковым именем, версией и региональными
стандартами, не опасаясь возникновения конфликтов.
Примечание Вспомогательный класс System.Reflection.AssemblyName по"
зволяет легко генерировать имя для сборки, а также получать отдельные
части имени сборки. Он поддерживает ряд открытых экземплярных
свойств: CultureInfo, FullName, KeyPair, Name и Version — и предоставля"
ет открытые экземплярные методы, такие как GetPublicKey, GetPublicKey
Token, SetPublicKey и SetPublicKeyToken.