Сборки

152

По умолчанию, код в проекте Silverlight размещается в одной сборке. Такой способ размещения кода оптимален для небольших приложений Silverlight. Однако часть кода можно разместить также в отдельной библиотечной сборке. Обычно библиотеки применяют для повторного использования кода в нескольких приложениях Silverlight, но иногда код размещают отдельно лишь для того, чтобы с ним можно было работать отдельно от приложения. Такой прием обычно используется, когда приложение создается разными командами разработчиков.

Создать библиотеку классов Silverlight несложно. Фактически она создается так же, как библиотечная сборка обычного приложения .NET. Сначала создайте в рабочей среде Visual Studio новый проект на основе шаблона Silverlight Class Library (Библиотека классов Silverlight). Затем добавьте в приложение Silverlight ссылку на него или на библиотечную сборку. Зависимая сборка будет автоматически скопирована в архив XAP при компиляции приложения.

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

Библиотеки классов предоставляют удобный способ совместного использования ресурсов разными приложениями. Ресурс можно внедрить в библиотеку классов, а затем извлечь в самом приложении. Использовать эту методику легко, нужно лишь правильно создать адрес URI. Для извлечения ресурса из библиотеки адрес URI в приложении должен быть записан в следующем формате:

/имя_библиотеки_классов;component/имя_файла_ресурса

Как видите адрес начинается с косой черты, представляющей корневую папку архива XAP. Сначала адрес указывает на зависимую сборку в архиве XAP, а затем — на ресурс в сборке.

В качестве примера рассмотрим сборку ResourceClassLibrary. Она содержит ресурс myimage.png, встроенный в сборку путем присвоения свойству Build Action значения Resource:

Ресурс в файле XAP

Ниже приведена разметка элемента Image, в котором используется ресурс myimage.png, хранящийся в библиотеке классов:

<Image Source="/ResourceClassLibrary;component/myimage.png" Stretch="None"/>

Загрузка сборки по требованию

В некоторых случаях код библиотеки классов используется редко, а часть пользователей его вообще не использует. Иногда библиотека классов содержит большой объем кода или (что более вероятно) большие файлы ресурсов (например, рисунки). Включение библиотеки в приложение приведет к увеличению размеров файла XAP и времени загрузки. В таких случаях рекомендуется создать отдельную сборку, загружаемую только по необходимости. Данный сценарий похож на загрузку ресурса по требованию. Ресурс находится в отдельном файле за пределами файла XAP, но на том же сайте.

Необходимо убедиться в том, что зависимая сборка случайно не попала в файл XAP. Для этого выделите в окне решений ссылку на сборку и в окне свойств установите для свойства Copy Local значение false. Затем убедитесь в том, что сборка скопирована в то же место, что и сайт. Если используется тестовый сайт ASP.NET, сборка должна быть скопирована в папку ClientBin. Выполнить приведенный ниже пример с помощью тестовой HTML-страницы не удастся, потому что при запуске приложения Silverlight непосредственно из файловой системы класс WebClient не работает.

Для загрузки сборки по требованию используются классы WebClient и AssemblyPart. Класс WebClient извлекает сборку, а класс AssemblyPart делает ресурс доступным для использования:

string uri = Application.Current.Host.Source.AbsoluteUri;
int i = uri.IndexOf("/ClientBin");

// Адрес URI содержит фрагмент /ClientBin, потому что 
// библиотека DLL находится в папке ClientBin
uri = uri.Substring(0, i) + "/ClientBin/ResourceClassLibrary.dll";

// Начало загрузки
WebClient web = new WebClient();
web.OpenReadCompleted += web_OpenReadCompleted;
web.OpenReadAsync(new Uri(uri));

Когда сборка загружена, метод AssemblyPart.Load() используется для ее загрузки в домен текущего приложения:

private void web_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
            if (e.Error != null)
            {
                // Сюда нужно добавить код, выводящий сообщение об ошибке 
            }
            else
            {
                AssemblyPart assemblypart = new AssemblyPart();
                assemblypart.Load(e.Result);
            }
}

После этого можно извлечь ресурс из сборки и создать на его основе экземпляры нужных типов. Дальше все происходит так, будто содержимое сборки было частью файла XAP с самого начала.

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

Если попытаться использовать незагруженную сборку, будет сгенерировано исключение. Однако оно генерируется не в коде, попытавшемся использовать сборку. Этот код игнорируется, а исключение передается обработчику события Application.UnhandledException. Исключение представляется объектом FileNotFoundException, а сообщение содержит имя недостающей сборки.

Кэширование сборок

Кэширование позволяет надстройке Silverlight загрузить сборки библиотечных классов и сохранить их в браузере. Благодаря кэшированию библиотеки не нужно загружать повторно при каждом запуске приложения.

Иногда ошибочно считают, что кэшированием можно заменить загрузку сборок по требованию. Однако два этих подхода приводят к разным результатам. Кэширование сборки уменьшает время запуска при повторном обращении к приложению или выполнении приложений, пользующимся одними и теми же средствами. В то же время загрузка по требованию уменьшает время запуска при каждом обращении к приложению, независимо от того, что находится в кэше и запускалось ли приложение перед этим.

Кэширование сборок полезно при использовании больших сборок, особенно если обращение к ним выполняется часто. Загрузка по требованию полезна при использовании редко загружаемых сборок, которые могут вообще не понадобиться приложению.

Сборки, создаваемые по умолчанию, не поддерживают кэширование. Чтобы можно было включить поддержку кэширования, необходимо удовлетворить два требования. Во-первых, сборка должна иметь строгое имя. Во-вторых, необходим файл XML специального типа, в котором описано содержимое сборки. Этот файл имеет расширение .extmap.xml. В следующих разделах рассматриваются оба требования.

Строгое имя

Чтобы сборку библиотечных классов можно было кэшировать, она должна иметь строгое имя (strong key name), которое уникально идентифицирует ее в кэше браузера и предотвращает конфликт имен. Для создания строгого имени сборки выполните действия, описанные ниже:

  1. Дважды щелкните на узле Properties (Свойства) в окне Solution Explorer (Обозреватель решений).

  2. Откройте вкладку Signing (Цифровые подписи).

  3. Установите флажок Sign the assembly (Подписать сборку).

  4. В раскрывающемся списке Choose a strong name key file (Выбор файла ключа строгого имени) выберите элемент <New>. Откроется диалоговое окно Create Strong Name Key (Создание ключа строгого имени).

    Цифровая подпись сборки
  5. Введите имя файла (например, MyKey.snk) и (необязательно) пароль.

  6. Щелкните на кнопке ОК. Программа Visual Studio создаст файл ключа и добавит его в проект библиотеки классов.

Начиная с этого момента при каждой компиляции проекта Visual Studio будет применять ключ для создания цифровой подписи окончательной сборки.

Прежде чем перейти к следующему этапу, необходимо выяснить маркер открытого ключа, используемого в цифровой подписи. К сожалению, Visual Studio не предоставляет простого способа извлечения маркера. Для этого нужно применить инструмент командной строки sn.exe.

При использовании Visual Studio 2012 выберите команду Microsoft Visual Studio 2012 --> Visual Studio Tools --> Developer Command Prompt for VS12. Будет выведено окно командной строки. Перейдите к папке, содержащей файл ключа, и выполните следующие две команды:

sn -р MyKey.snk МуКеу.bin
sn -t MyKey.bin

По завершении второй команды появится приблизительно такое сообщение:

Получение ключа сборки

Полученный таким образом маркер открытого ключа понадобится на следующем этапе — при создании файла .extmap.xml для сборки.

Файл .extmap.xml

Это обычный текстовый файл, содержащий код XML. Его имя совпадает с именем сборки. Например, если сборка библиотечных классов называется ResourceClassLibrary.dll, нужно создать файл ResourceClassLibrary.extmap.xml. Наличие файла .extmap.xml сообщает надстройке Silverlight о том, что сборка поддерживает кэширование.

Чтобы облегчить себе жизнь, добавьте файл .extmap.xml в проект библиотеки классов. Для этого выделите его в окне Solution Explorer и присвойте свойству Build Action значение None, а свойству Copy to Output Directory — значение Copy always. При компиляции это обеспечит размещение файла в той же папке, что и файл сборки. На рисунке ниже показана библиотека классов с файлом .extmap.xml:

Файл .extmap.xml

Файл .extmap.xml легче всего создать на основе образца, приведенного ниже, откорректировав его для вашей сборки:

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <assembly>
    <name>ResourceClassLibrary</name> 
    <version>1.0.0.0</version>
    <publickeytoken>406cf67f825cf3c3</publickeytoken> 
    <relpath>ResourceClassLibrary.dll</relpath>
    <extension downloadUri="ResourceClassLibrary.zip" />
  </assembly>
</manifest>

Имя и версия должны соответствовать вашей сборке. Маркер открытого ключа идентифицирует строгое имя, используемое для создания цифровой подписи сборки. Извлечь маркер открытого ключа можно с помощью утилиты sn.exe, как описано выше. Относительный маршрут содержит имя сборки. И наконец, атрибут downloadUri предоставляет наиболее важную информацию — сообщает приложению, где найти упакованную загружаемую сборку.

Существуют два способа установки атрибута downloadUri. Первый способ — можно всего лишь присвоить ему имя файла, как в приведенном выше примере. При переходе к кэшированию сборки в приложении программа Visual Studio сожмет сборку библиотеки классов (в данном примере ResourceClassLibrary.dll) и разместит сжатый файл (ResourceClassLibrary.zip) рядом с файлом ХАР. Этот же способ применяется в сборках надстройки Silverlight.

Программа Visual Studio сжимает сборку методом ZIP, однако присваивать файлу расширение .zip не обязательно. Если веб-сервер требует другого расширения, примените его в атрибуте downloadUri. Если в downloadUri используется одно и то же имя файла для разных сборок, Visual Studio сожмет все сборки в один файл ZIP.

Другой способ состоит в использовании абсолютного адреса URI в атрибуте downloadUri:

<extension downloadUri="http://www.mysite.сош/assemblies/v1/ResourceClassLibrary.zip" />

В этом случае Visual Studio не пакует сборку при компиляции приложения. Программа считает, что вы уже разместили сборку в Интернете. Это обеспечивает мощный способ совместного использования библиотек разными приложениями. Сборка должна быть размещена в том же домене, что и приложение Silverlight, или должен быть явно разрешен кроссдоменный доступ.

Когда файл .extmap.xml существует, сборку можно кэшировать. Чтобы поэкспериментировать с кэшированием, создайте приложение, в котором используется библиотека классов. Включите поддержку кэширования, установив флажок Reduce XAP size by using application library caching (Уменьшить размеры файла XAP путем кэширования библиотеки приложения). Скомпилируйте приложение. В папке Debug будет размещен файл ZIP сборки:

Сжатая сборка, готовая к кэшированию
Пройди тесты
Лучший чат для C# программистов