На переднем крае

Управление доставкой динамического содержимого в Silverlight. Часть 1.

Дино Эспозито (Dino Esposito)

Загружаемый файл с кодом доступен в коллекции кода MSDN
Обзор кода в интерактивном режиме

Cодержание

Размер приложений Silverlight
Динамически создаваемый код XAML
Динамически создаваемый пакет XAP
Содержимое «по требованию»
Кэширование загружаемого содержимого
Средство загрузки файлов
Загрузка только данных XAML
Работа с пакетами XAP
Обработка содержимого XAP
Заключение

Пользователи любого функционально насыщенного веб-приложения (RIA) испытывают обоснованную озабоченность относительно безопасности и размера загружаемых файлов. Приложения Silverlight поддерживаются подмножеством полнофункциональной среды Microsoft .NET Framework и, по существу, обладают потенциальной возможностью выполнять операции, наносящие вред локальному компьютеру пользователя. По этой причине группа Silverlight разработала новую модель безопасности, делающую невозможным обращение приложений ни к одному из важных с точки зрения безопасности классов Core CLR (выпуск .NET Framework, поддерживающий Silverlight). Подробнее о модели безопасности Silverlight можно прочитать в статье «Program Silverlight with the CoreCLR» (Программирование для Silverlight с помощью CoreCLR), а о создании приложений Silverlight — в статье «Get Started Building a Deeper Experience across the Web» (Навыки создания более насыщенного интерфейса пользователя через Интернет).

На самом деле загрузка подключаемого модуля Silverlight не представляет сложностей, поскольку эта операция занимает всего несколько секунд и выполняется только один раз. А что можно сказать о размере загружаемых приложений?

В статье этого месяца рассматривается вопрос загрузки приложений Silverlight. Сначала я продемонстрирую способ динамического создания кода XAML. Затем будет рассмотрен способ динамического активирования компонентов приложения строго на основании запроса пользователя. Некоторые конкретные компоненты приложения, которые трудно реализовать посредством основного потока кода, могут быть реализованы отдельно и, что более важно, могут быть отдельно загружены, и при этом их легко интегрировать в основной интерфейс пользователя.

Размер приложений Silverlight

После того, как пользователь установил подключаемый модуль Silverlight, у него имеются все сборки системы, которые могут потребоваться приложению Silverlight. Это означает, что файл загрузки ограничен сборкой, содержащей приложение, с добавлением всех пользовательских сборок, на которые имеются ссылки. В итоге размер файла для загрузки приложения достигает зачастую десятков килобайт. Отмечу, что эта оценка применима к версии RTM платформы Silverlight 2 и к коду, скомпилированному в режиме release.

Безусловно, приложение может занимать гораздо больше места, в особенности если в него входят длинные алгоритмы, графическое и мультимедийное содержимое или анимации. В случае громоздких приложений, когда время загрузки становится проблемой, можно выбрать один из двух основных вариантов. Первый вариант заключается в создании потока содержимого Silverlight тем способом, который обсуждался на веб-узле по адресу silverlight.live.com. Другой вариант состоит в разбиении приложения на независимые части, которые можно загружать по отдельности и по запросу.

Динамически создаваемый код XAML

Подключаемый модуль Silverlight предназначен, по существу, для отображения содержимого в формате XAML. Если код XAML сопровождается некоторым кодом поддержки, тогда подключаемый модуль обрабатывает код для создания пользовательского интерфейса и поддержки любого закодированного поведения или эффектов. Если требуется загрузить только код XAML, можно указать непосредственно его URL-адрес; в противном случае для ссылки на пакет Silverlight можно использовать расширение XAP.

В пакет XAP входит манифест и одна или несколько сборок. Одна из этих загрузок содержит точку входа приложения; остальные сборки — это сборки, на которые имеются ссылки. XAML для пользовательского интерфейса хранится в файлах ресурсов сборки точки входа. Пакет XAP создается расширением Visual Studio 2008 для Silverlight 2 при создании и сборке проекта.

Единственное, что умеет делать подключаемый модуль Silverlight — это обработка потоков XAML и XAP. Однако для загрузки такого содержимого подключаемому модулю не обязательно указывать физический ресурс XAML или XAP на сервере. Можно, например, указать подключаемому модулю URL-адрес, возвращающий динамически создаваемое содержимое XAML или XAP.

На рис. 1 показан пример обработчика HTTP в ASP.NET, возвращающего оперативно созданный код XAML. Метод ProcessRequest устанавливает тип содержимого объекта Response, а затем записывает некоторое содержимое XAML, например составленный динамически код XAML, на основе данных настройки, параметров или условий этапа выполнения. Настраивая свойство Expires объекта Response, можно также предотвратить кэширование файла ресурса на клиентском компьютере. Это удобно, если содержимое, с которым вы работаете, периодически изменяется и требует обновления.

Рис. 1 Обработчик HTTP, возвращающий код XAML

<%@ WebHandler Language="C#" Class="XamlGenHandler" %>

using System;
using System.Web;

public class XamlGenHandler : IHttpHandler 
{
    public void ProcessRequest (HttpContext context) 
    {
        // Prevent caching of the response
        context.Response.Expires = -1;

        // Set the type of data we're returning
        context.Response.ContentType = "text/xaml";

        // Create some XAML and return it down the wire
        context.Response.Write("<Canvas xmlns=
            'http://schemas.microsoft.com/client/2007' " +
            "xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>" +
            "<TextBlock Foreground='black' Padding='10' FontSize='20'>
             <Run>XAML content</Run><LineBreak/>" + 
            "<Run>[generated " + DateTime.Now.ToLongTimeString() + "]</Run>" +
            "</TextBlock></Canvas>");
    }

    public bool IsReusable 
    {
        get {return true;}
    }

}

Динамически создаваемый пакет XAP

Процедура возврата динамически созданного пакета XAP не слишком отличается от возврата необработанного текста XAML, за исключением того, что пакет XAP не является обычным текстовым файлом. Пакет XAP представляет собой файл ZIP, в который входит манифест XML и одна или несколько сборок. Используя формат пакета, рабочая группа свела к минимуму число циклов обработки, необходимых для загрузки всего содержимого, требуюемого для приложения Silverlight. На рис. 2 показан обработчик HTTP в ASP.NET, записывающий содержимое файла XAP в поток ответа HTTP.

Рис. 2 Обработчик HTTP, возвращающий пакет XAP

<%@ WebHandler Language="C#" Class="XapGenHandler" %>

using System;
using System.Web;

public class XapGenHandler : IHttpHandler 
{
    public void ProcessRequest (HttpContext context) 
    {
        // XAP file to return 
        string xapFile = "...";

        // Set the type of data we're returning
        context.Response.ContentType = "application/octet-stream";

        // Create some XAML and return it down the wire
        content.Response.WriteFile(xapFile);
    }


    public bool IsReusable 
    {
        get {return true;}
    }

}

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

Возвращая содержимое XAP, вы устанавливаете тип application/octet-stream для содержимого ответа — тип MIME, который обычно определяет обобщенное двоичное содержимое.

Для привязки подключаемого модуля к обработчику HTTP или любой другой выбранной вами конечной точке используются обычные методики программирования Silverlight. Например, можно использовать серверный элемент управления Silverlight на странице ASP.NET.

<asp:Silverlight ID="Xaml1" runat="server" 
    Source="~/xap.ashx" 
    MinimumVersion="2.0.30523" 
    Width="100%" 
    Height="100%" />

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

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

Содержимое по запросу

Silverlight 2 предоставляет функционально насыщенный и универсальный интерфейс API для загрузки по запросу кода и/или XAML и внедрения его в существующую объектную модель документа XAML.

Все визуальные элементы дерева XAML обладают свойством под именем Children, которое можно использовать для программного добавления и удаления дочерних элементов любого размера. Например, можно добавить весь пользовательский элемент управления, загруженный с этого же сервера или даже с доверенного удаленного сервера рассылки. Вот пример строки кода:

StackPanel1.Children.Add(downloadedContent);

Пользовательский элемент управления, представленный аргументом, добавляется в коллекцию Children элемента XAML с именем StackPanel. Визуализация выполняется незамедлительно, и пользовательский интерфейс обновляется в режиме реального времени.

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

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

Кэширование загружаемого содержимого

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

Отмечу, что если требуется загрузить ресурс XAP из обозревателя, кэширование можно контролировать с помощью имеющихся на странице параметров, которые обычно вставляются с помощью метатегов или атрибутов директив ASP.NET. Если ресурс XAP требуется загрузить с помощью обработчика HTTP, как в предыдущем примере, в этом случае можно управлять кэшированием для конкретного запроса.

Еще один вопрос, на который следует обратить внимание, заключается в том, что кэшируется исходное содержимое XAP, включая сборки и XAML. Следовательно, работающее приложение может программно модифицировать исходный код XAML. Однако, такие изменения не будут кэшироваться автоматически, и точно так же не будет выполняться изолированное кэширование любого ресурса, извлекаемого из пакета XAP (мультимедийные данные, изображения и т.п.). Таким образом, когда бы пользователь ни посетил страницу, пакет XAP не загружается повторно (если только он не является просроченным), но все ресурсы извлекаются повторно. Более того, утрачиваются все изменения, которые могли быть внесены в эти ресурсы в предыдущих сеансах. Для сохранения изменений объектной модели документа XAML необходимо организовать свой собственный специальный кэш. (Эта современная методика будет обсуждаться во второй части статьи, посвященной этой теме.)

Наконец, отмечу, что за пакетом XAP, сохраненным в кэше обозревателя, следит пользователь. Елси пользователь в какой-то момент времени решит очистить кэш, то все содержащиеся в нем данные будут утрачены, включая пакеты XAP. Для постоянного хранения пакетов Silverlight XAP необходимо предусмотреть отдельное хранилище (обсуждение этой темы также оставлено до второй части статьи).

Средство загрузки файлов

При написании приложений Silverlight следует помнить о том, что все требуемые ресурсы, которые не включены в пакет XAP приложения, необходимо самостоятельно загрузить с сервера. Класс WebClient является основным средством Silverlight, предназначенным для организации загрузки файлов дополнительных ресурсов. Этот класс предоставляет несколько асинхронных методов для передачи данных веб-ресурсу и получения данных с веб-ресурса. Это происходит следующим образом.

WebClient wc = new WebClient();
wc.DownloadStringCompleted += 
     new DownloadStringCompletedEventHandler(callback);
wc.DownloadStringAsync(address);

Метод DownloadStringAsync использует команду HTTP GET и получает ответ формата URL в виде строки. Ниже показано, как эту строку получает соответствующий обратный вызов.

void callback(object sender, DownloadStringCompletedEventArgs e)
{
  if (e.Error != null)
     return;

  string response = e.Result;
...
}

Вскоре вы увидите, что этот метод идеально подходит для загрузки обычного XAML, не сопровождаемого кодом поддержки. Для программной загрузки двоичных данных, например пакета XAP, требуется поток и несколько иной подход. Класс WebClient по-прежнему полезен, поскольку он предоставляет подходящий метод в OpenReadAsync.

WebClient wc = new WebClient();
wc.OpenReadCompleted += 
     new OpenReadCompletedEventHandler(callback);
wc.OpenReadAsync(address);

Структура соответствующего обратного вызова точно такая же, как в предыдущем случае. В конечном счете, для получения простой строки используется метод DownloadStringAsync; для получения потока данных используется метод OpenReadAsync. Выбор между загрузкой строки или потока является, главным образом, вопросом предпочтения и зависит, по существу, от того, как предполагается использовать получаемые данные.

Обратите также внимание на то, что WebClient предоставляет пару методов для написания удаленного URL-адреса: метод UploadStringAsync для создания строки и метод OpenWriteAsync для загрузки данных на URL-адрес с помощью потока.

Свойство Headers можно использовать для указания дополнительных заголовков, поскольку по умолчанию данный класс не указывает никаких заголовков. Однако необходимо обратить внимание на то, что некоторые из созданных заголовков платформа вырезает и управляет ими внутренним образом. К ним относятся Referer, Connection и User-Agent. Заголовок Content-Type, если он создан, сохраняется.

Когда дело доходит до загрузки ресурсов, класс WebClient, прежде чем пытаться установить подключение, прозрачно использует кэш обозревателя. Если в кэше нет ресурса XAML или XAP, класс приступает к загрузке. Процесс загрузки содержимого из приложения Silverlight выполняется в результате совместной работы среды выполнения Silverlight и внутренного интерфейса API, предоставляемого размещающим обозревателем подключаемому модулю. Это означает, что под прикрытием WebClient среда выполнения Silverlight обменивается информацией с «песочницей» обозревателя, чтобы проверить, присутствует ли в кэше запрошенный ресурс. Если нет, Silverlight переходит к выполнению своих собственных политик безопасности для авторизации запроса. Когда данные, в конце концов, возвращаются из конечной точки, среда выполнения Silverlight кэширует их локально посредством служб обозревателя в полном соответствии с текущими политиками кэширования.

К классу WebClient и другим классам HTTP из пространства имен Silverlight System.Net применяется ряд ограничений безопасности. В частности, при загрузке посредством потока класс WebClient поддерживает только схемы HTTP и HTTPS, а при загрузке чистого XAML — схему FILE. Доступ с использованием разных схем полностью запрещен, поэтому невозможно классу WebClient указать, например, ресурс HTTPS, если страница размещения загружается посредством HTTP (или наоборот). Запрос WebClient может, вообще говоря, достичь URL-адреса в зоне другого обозревателя, но не в том случае, когда он пытается переместиться из некоторой зоны Интернета в зону с более строгими ограничениями. В настоящее время Silverlight поддерживает зоны только в операционной системе Windows.

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

Один объект WebClient не в состоянии обрабатывать одновременно несколькo запросов. Необходимо проверить свойство IsBusy, имеющее логическое значение, чтобы определить, может ли ваш код безопасным образом поместить новый запрос посредством этого же экземпляра WebClient. При использовании нескольких объектов WebClient (возможно, на разных потоках) можно одновременно запустить несколько загрузок.

Загрузка только данных XAML

Посмотрим, как используется WebClient для загрузки данных XAML и включения их в визуальное дерево. В приложениях Silverlight 2 динамическая загрузка простых данных XAML совсем не обязательно обеспечивает требуемые вам возможности программирования. Строка XAML должна быть простым кодом XAML, не содержащим ссылок, требующих разрешения на этапе выполнения, таких как привязки или ссылки на стили и события.

После того, как строка XAML загружена, используется класс XamlReader для преобразования ее в элемент интерфейса пользователя, который можно добавить в существующую объектную модель документа. В следующем далее коде показано, как программным образом загрузить строку XAML с URL-адреса. Отмечу, что URL-адрес потребуется предоставить в виде объекта Uri.

WebClient client = new WebClient();
client.DownloadStringCompleted += 
   new DownloadStringCompletedEventHandler(OnDownloadCompleted);
Uri uri = new Uri("xaml.ashx", UriKind.Relative);
client.DownloadStringAsync(uri);

URL-адрес может указывать на ресурс с простым кодом XAML или на конечную точку, возвращающую ответ text/xaml. В следующем коде загруженный код XAML обрабатывается и добавляется к местозаполнителю в визуальном дереве.

void OnDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    // Parse XAML to a UI element 
    string xaml = e.Result;
    UIElement dom = XamlReader.Load(xaml) as UIElement;

    // Append to the DOM
    Placeholder.Children.Clear();
    Placeholder.Children.Add(dom);
}

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

Сериализация XAML, выполняемая посредством классов XamlReader и XamlWriter, основывается на принципе отмены ссылок расширения и сохранении значений этапа выполнения поверх параметров этапа разработки. А что, если требуется загрузить содержимое XAML и настроить его до отображения, например посредством динамической привязки данных? Возможности встроить привязки в исходный код XAML не существует, но в загруженном коде XAML можно определить местозаполнители, извлечь их с помощью синтаксического анализа и настроить их программным образом на любое требуемое значение. Однако в Silverlight 2 более предпочтительным решением является, безусловно, загрузка пакета XAP.

Работа с пакетами XAP

Пакет XAP содержит всё приложение Silverlight, пользовательский интерфейс которого состоит, по существу, из пользовательского элемента управления, являющегося на деле просто контейнером разметки и кода XAML.

Как упоминалось, в пакет XAP входит одна или несколько сборок, отслеживаемых файлом манифеста. Обработка пакета XAP, помимо загрузки, влечет два дополнительных этапа. Необходимо выделить основную сборку и затем создать экземпляр класса точки входа, запускающий загруженное приложение. Излишне говорить о том, что в этом случае в XAML можно использовать привязку, стили, события и все, что потребуется. При работе с пакетом XAP именно среда выполнения Silverlight, а не интерфейс API сериализации, обрабатывает XAML и затем разрешает ссылки. С точки зрения возможностей программирования это совершенно другой подход.

Для загрузки и обработки пакета XAP тpебуется несколько больший объем работы, чем при простом создании объектной модели из строки. Часть этой работы (как правило, загрузку содержимого и извлечение сборки) можно переместить в допускающий повторное использование класс загрузчика (см. рис. 3).

Рис. 3. Динамическая загрузка пакета XAP

public partial class Page : UserControl
{
    private UIElement content = null;
    private TabItem item = null;

    public Page()
    {
        InitializeComponent();
    }

    private void chkNewContent_Click(object sender, RoutedEventArgs e)
    {
        bool shouldDisplay = (sender as CheckBox).IsChecked.Value;   

        if (shouldDisplay)
        {
            if (!IsContentAvailable())
                DownloadContent();
            else
                ShowContent();
        }
        else
        {
            HideContent();
        }
    }

    private bool IsContentAvailable()
    {
        return (content != null);
    }

    private void DownloadContent()
    {
        Downloader dl = new Downloader();
        dl.XapDownloaded += 
            new EventHandler<XapEventArgs>(OnPackageDownload);
        dl.LoadPackage("more.xap", "more.dll", "More.ExtraTab");
    }

    void OnPackageDownload(object sender, XapEventArgs e)
    {
        content = e.DownloadedContent;
        ShowContent();
    }

    private void HideContent()
    {
        this.TabList.Items.Remove(item);
    }

    private void ShowContent()
    {
        item = new TabItem();
        item.Header = "Extra tab";
        item.Content = content;
        this.TabList.Items.Add(item);
    }
}

В коде на рис. 3 показан пример приложения со вкладками, которое загружает новую вкладку, когда пользователь в первый раз устанавливает флажок. В этом случае загружается новый пакет XAP, и пользовательский элемент управления, содержащийся в его пользовательском интерфейсе, вставляется во вновь созданный TabItem. Скрытие содержимого из вновь загруженного пакета является простой операцией клиента. А повторное его отображение не требует второго цикла по следующим двум причинам: содержимое кэшировано в памяти, а пакет, из которого оно было создано, кэширован в кэше обозревателя.

На рис. 4 показан пользовательский интерфейс этого примера приложения. Содержимое, вставленное в дополнительную вкладку, происходит из нового проекта приложения Silverlight. С точки зрения развертывания всё, что вам требуется сделать, это сохранить пакет XAP в папке ClientBin размещающего веб-узла (папка, в которой WebClient по умолчанию ищет соответствующее содержимое) или в любом другом месте, которого WebClient может достичь безопасным образом.

fig04.gif

Рис. 4 Приложение, способное динамически загружать части пользовательского интерфейса

Теперь давайте изучим код вспомогательного класса Downloader. Отмечу, что класс Downloader, используемый в этом примере, является внутренним классом и не имеет никакого отношения к объекту Downloader платформы Silverlight, который доступен для вызывающего кода JavaScript. Объект загрузчика JavaScript является, по существу, оберткой WebClient, вызываемой из сценария.

Обработка содержимого XAP

Класс Downloader использует WebClient для загрузки пакета XAP, а затем извлекает сборку, содержащую приложение, из сжатого потока и создает экземпляр указанного корневого класса. Вся эта логика спрятана за относительно простым программным фасадом, созданным из метода LoadPackage и события XapDownloaded. Этот метод имеет следующую сигнатуру.

public void LoadPackage(
    string xapURL, string assemblyName, string className);

Он получает URL-адрес пакета, имя сборки, которую необходимо извлечь из пакета, и имя класса для создания его экземпляра. Как было упомянуто, этот класс является кодом поддержки файла интерфейса XAML.

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

public event 
    EventHandler<XapEventArgs> XapDownloaded;

Класс аргумента события возвращает следующую информацию.

public class XapEventArgs : EventArgs
{
  public UserControl DownloadedContent;
}

Давайте разберем логику метода LoadPackage. Метод использует двоичный интерфейс класса WebClient для указания на пакет XAP.

void LoadPackage(string package, string asm, string cls)
{
    assemblyName = asm;
    className = cls;

    Uri address = new Uri(package, UriKind.RelativeOrAbsolute); 
    WebClient client = new WebClient();
    client.OpenReadCompleted += 
       new OpenReadCompletedEventHandler(OnCompleted);
    client.OpenReadAsync(address);
}

Загрузка продолжается асинхронно и по завершении создает событие OpenReadCompleted. На рис. 5 показана реализация обработчика события.

Рис. 5 Загрузка завершена

void OnCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if (PackageDownloaded == null)
        return;

    if (e.Error != null)
        return;

    // Load a particular assembly from the XAP package
    Assembly a = GetAssemblyFromPackage(assemblyName, e.Result);

    // Get an instance of the XAML object
    object page = a.CreateInstance(className);  

    // Fire the event
    XapEventArgs args = new XapEventArgs();
    args.DownloadedContent = page as UserControl;
    XapDownloaded(this, args);
}

В отсутствие ошибок вспомогательная функция извлекает указанную сборку из пакета и получает требуемый для добавления экземпляр класса пользовательского элемента управления в фоновом коде блока XAML. Затем создается пользовательское событие для вызывающего кода, чтобы можно было обработать поддерево XAML. В этом месте остается обсудить следующее: детали того, каким образом сборка извлекается из сжатого потока, загруженного с URL-адреса. Этот код показан на рис. 6. Это стандартный код для извлечения сборки из пакета XAP. StreamResourceInfo и Application.GetResourceStream также широко используются для извлечения пакетов ресурсов, таких как изображения или мультимедийное содержимое, из текущего пакета XAP.

Рис. 6. Извлечение сборки из пакета XAP

Assembly GetAssemblyFromPackage(string assemblyName, Stream xap)
{
    // Local variables
    Uri assemblyUri = null;
    StreamResourceInfo resPackage = null;
    StreamResourceInfo resAssembly = null;
    AssemblyPart part = null;

    // Initialize
    assemblyUri = new Uri(assemblyName, UriKind.Relative);
    resPackage = new StreamResourceInfo(xap, null);
    resAssembly = Application.GetResourceStream(resPackage, assemblyUri);

    // Extract an assembly 
    part = new AssemblyPart();
    Assembly a = part.Load(assemblySri.Stream);
    return a; 
}

Заключение

Предполагается, что на пользовательской машине приложения Silverlight будут быстро загружаться и устанавливаться и быстро работать. Управляемый код работает лучше, чем интрепретируемый код JavaScript, поэтому производительность будет действительно высокой. Но, поскольку загрузка больших приложений Silverlight или приложений, требующих объемного внешнего графического или мультимедийного содержимого, может вызвать нежелательную задержку, ситуацию можно исправить, разбивая загрузку на несколько этапов. Еще лучше запрограммировать возможность проводить загрузку в несколько этапов по запросу.

Класс WebClient предлагает эффективный и асинхронный интерфейс программирования API для загрузки любых ресурсов, к которым можно получить доступ по Интернету. Расширяемая модель для объектной модели Silverlight позволяет быстро внедрять в существующую структуру любые изменения. Наконец, основанный на потоках интерфейс API, центральную роль в котором играет класс StreamResourceInfo, облегчает извлечение содержимого из ресурсов сборок и пакетов XAP.

Все загружаемые ресурсы кэшируются обозревателем. Однако этот тип кэширования не является неизменным. Во второй части этой статьи будет использовано изолированное хранилище, обеспечивающее длительное хранение загруженного содержимого на компьютере пользователя, что экономит большое число потенциальных циклов приемов-передач. О других приятных возможностях Silverlight читайте в статье «Silverlight Tips, Tricks, and Best Practices» (Советы, приемы работы и практические рекомендации по Silverlight) в рубрике Джеффа Просайза «Wicked Code» (Коварный код).

Свои вопросы и комментарии для Дино отправляйте на cutting@microsoft.com.

Дино Эспозито (Dino Esposito) работает архитектором ПО в компании IDesign и является одним из соавторов книги Microsoft .NET: Создание архитектуры приложений для предприятия (Издательство «Microsoft Press», 2008). Проживая в Италии, Дино часто выступает на различных профессиональных мероприятиях по всему миру. Связаться с ним можно в блоге по адресу weblogs.asp.net/despos.