silverlight:在 Silverlight 中管理动态内容交付 第 1 部分

  本文举例源代码或素材下载

在 Silverlight 中管理动态内容交付<img src='/icons/58281dou.gif' />第 1 部分目录

  Silverlight 应用大小

  动态生成 XAML

  动态生成 XAP

  请求内容

  缓存Cache下载内容

  下载工具

  下载仅含 XAML 数据

  使用 XAP

  处理 XAP 内容

  整理总结

  任何使用富 Internet 应用 (RIA) 用户都关注安全性和下载大小问题Silverlight 应用受到完整 Microsoft .NET Framework 子集支持因此可能会对本地用户计算机执行有害操作为此Silverlight 团队(Team)开发了个全新安全模型可防止应用核心 CLR(.NET Framework Silverlight 版本)中任何安全关键类您可以从文章“使用 CoreCLR 编写 Silverlight”中了解有关 Silverlight 安全模型更多信息从“开始在整个网站WebSite积累更深入体验”中了解有关构建 Silverlight 应用详细内容

  下载 Silverlight 插件并不是问题核心所在此操作只需几秒钟且只能运行但是所下载应用大小会有什么影响呢?

  在本月专栏中我将解决 Silverlight 应用下载问题首先我将介绍说明如何动态生成 XAML然后我将讨论如何严格地根据每个用户请求动态启用应用功能在随后可以单独实现些使用主代码流难以实现特定于应用功能更为重要可以分别下载它们而且可以轻松地和主用户界面相集成

  Silverlight 应用大小

  用户安装了 Silverlight 插件后他就拥有了 Silverlight 应用可能会需要所有系统这意味着下载仅限于包含该应用集以及任何引用自定义最后应用下载文件大小通常为数万字节请注意此估计值仅适用于 RTM 版本 Silverlight 2 以及在发布模式下编译代码

  当然该应用占用空间可能会更大尤其是当其包含长算法、图形和媒体内容或动画时要处理下载时间过长大型应用般可采用以下两种思路方法种是流式传输 Silverlight 内容如 silverlight.live.com 上所述种是将应用拆分成可以按需分别下载独立片段

  动态生成 XAML

  Silverlight 插件本质上设计用于显示 XAML 内容如果 XAML 附带了些代码隐藏则该插件会对代码进行处理以生成用户界面并支持任何编码行为或效果如果您要下载是 XAML那么可以通过 URL 直接指向该 XAML;如果不是则可以通过 XAP 扩展名来引用 Silverlight

  XAP 包内含指令清单和或多个其中集包含应用入口点;其他集仅仅是引用用户界面 XAML 存储在入口点资源中在创建和编译项目时Silverlight 2 Visual Studio 2008 扩展会创建个 XAP

  XAML 和 XAP 流都属于 Silverlight 插件知道如何处理但是要下载此类内容您不必将该插件指向服务器上物理 XAML 或 XAP 资源您可以将该插件指向某个 URL例如可以指向返回动态生成 XAML 或 XAP 内容 URL

  图 1 显示了个举例 ASP.NET HTTP 处理它将返回动态创建某些 XAMLProcessRequest 思路方法在 Response 对象上设置内容类型然后根据配置数据、参数或运行时条件撰写某些 XAML 内容(如动态合成 XAML)通过设置 Response 对象 Expires 属性您还可以禁止在客户端上缓存Cache资源如果您所处理内容会定期改动并需要刷新则这可能会有所帮助

在 Silverlight 中管理动态内容交付<img src='/icons/58281dou.gif' />第 1 部分图 1 返回 XAML HTTP 处理

<%@ WebHandler Language="C#" Class="XamlGenHandler" %>
using ;
using .Web;
public XamlGenHandler : IHttpHandler
{
  public void ProcessRequest (HttpContext context)
  {
    // Prevent caching of the response
    context.Response.Expires = -1;
    // Set the type of data we're ing
    context.Response.ContentType = "text/xaml";
    // Create some XAML and 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 { true;}
  }
}


  动态生成 XAP

  返回动态生成 XAP 包和返回原始 XAML 文本 2者差别并不大只不过 XAP 包不是纯文本文件罢了XAP 包是个 ZIP 文件它包含 XML 指令清单和或多个通过使用包格式团队(Team)可以最大程度地减少下载 Silverlight 应用请求全部内容所需往返次数图 2 显示了个 ASP.NET HTTP 处理它将 XAP 文件内容写入到 HTTP 响应流中

在 Silverlight 中管理动态内容交付<img src='/icons/58281dou.gif' />第 1 部分图 2 返回 XAP HTTP 处理

<%@ WebHandler Language="C#" Class="XapGenHandler" %>
using ;
using .Web;
public XapGenHandler : IHttpHandler
{
  public void ProcessRequest (HttpContext context)
  {
    // XAP file to
     xapFile = "...";
    // Set the type of data we're ing
    context.Response.ContentType = "application/octet-stream";
    // Create some XAML and it down the wire
    content.Response.WriteFile(xapFile);
  }
  public bool IsReusable
  {
    get { true;}
  }
}
  举例代码从现有文件中读取 XAP 数据显然如果在项目中嵌入个 ZIP 库则可以轻松地动态组合包(首先将区别 DLL 组合在然后创建适当 XML 指令清单文件)

  如果想返回 XAP 内容可将响应内容类型设置为 application/octet-stream这是种 MIME 类型通常用于标识通用 2进制内容

  要将该插件和 HTTP 处理或您选择任何其他端点相关联可使用常见 Silverlight 编程技术例如您可以在 ASP.NET 页面中使用 Silverlight 服务器Control控件:

<asp:Silverlight ID="Xaml1" runat="server"
  Source="~/xap.ashx"
  MinimumVersion="2.0.30523"
  Width="100%"
  Height="100%" />
  在这两个举例中Silverlight 应用工厂均位于 Web 服务器上如果宿主页面需要动态指示要下载内容则这不失为种不错思路方法

  但是这只是种可能情况还有另种情况可能更常见即需要下载当前 Silverlight 应用可选组件在这种情况下选择和下载外部内容逻辑全部位于客户端上运行 Silverlight 插件中

  请求内容

  Silverlight 2 为按需下载代码和/或 XAML 提供了个丰富而又强大 API可用来下载内容并将其插入到现有 XAML 文档对象模型中

  XAML 树所有可视元素都有个名为 Children 属性可用来以编程方式添加或删除任意大小子元素例如您可以附加从同服务器甚至是从信任可选远程服务器下载整个用户Control控件举例如下行所示:

StackPanel1.Children.Add(downloadedContent);  由参数表示用户Control控件被添加到 StackPanel XAML 元素 Children 集合中呈现是即时性而用户界面是实时更新

  您可以做不仅仅是下载内容并将其附加到现有文档对象模型中您可以执行更多其他操作例如您可以在本地将其缓存Cache到应用本地存储中并检查自己缓存Cache是否存在请求内容在确认完毕后再向服务器发出新请求

  此思路方法使您能够永久存储下载内容但在某些情况下这可能有些多余种简单思路方法不需要任何额外工作:让浏览器为您缓存Cache XAP 资源

  缓存Cache下载内容

  从 Web 服务器获得 XAP 包对浏览器而言没有任何特殊含义因此浏览器在缓存Cache从 Web 服务器获得任何其他内容同时也会缓存Cache它但这切都遵守在宿主 HTML 页面中由请求或类似 meta 标记中 cache-control 和 "expires" HTTP 标头所确定请求缓存Cache策略

  请注意当遇到需要下载到浏览器中 XAP 资源时可以在通常使用 meta 标记或 ASP.NET 指令属性插入页面中通过进行些设置来控制缓存Cache如果 XAP 资源将要通过 HTTP 处理下载(如的前举例所示)则您可以控制特定请求缓存Cache

  值得注意另外点是这里被缓存Cache是原始 XAP 内容(包括集和 XAML)因此正在运行应用可以通过编程方式修改原始 XAML但是这种更改不会被自动缓存Cache同样您从 XAP 包中提取任何资源(媒体、图像等)也不会被单独缓存Cache这样每次用户访问该页面时都不会重新下载 XAP 包(除非已过期)但会重新提取所有资源此外您在先前会话中对这些资源所做所有更改也将丢失要保留对 XAML 文档对象模型所做更改必须安排您自己定制缓存Cache(这是种很酷思路方法我将在本主题第 2 部分对此加以介绍)

  最后还要注意保存在浏览器缓存Cache中 XAP 存留完全取决于用户如果用户决定在某个时间清除缓存Cache则其中所有内容都将丢失(包括 XAP 包)要永久存储 Silverlight XAP 必须求助于独立存储(此主题也安排在第 2 部分进行介绍)

  下载工具

  在编写 Silverlight 应用要记住届时需要用到但却未打包到应用 XAP 中所有资源都必须从服务器显式下载WebClient 类是可用来安排附加资源下载主要 Silverlight 工具它提供了些异步思路方法可用于将数据发送到 Web 资源以及从 Web 资源接收数据下面介绍它工作原理:

WebClient wc = WebClient;
wc.DownloadStringCompleted
   DownloadStringCompletedEventHandler(callback);
wc.DownloadStringAsync(address);
  DownloadStringAsync 思路方法操控 HTTP GET 并捕获 URL 响应作为串由相关联回调接收如下所示:

void callback(object sender, DownloadStringCompletedEventArgs e)
{
  (e.Error != null)
   ;
  response = e.Result;
...
}
  稍后您会看到此思路方法非常适合于下载没有附加任何代码隐藏纯 XAML要以编程方式下载 2进制数据(如 XAP 包)您需要用到流并需要使用种略微区别思路方法这时 WebClient 类仍很有帮助它在 OpenReadAsync 中提供了种非常适合思路方法:

WebClient wc = WebClient;
wc.OpenReadCompleted
   OpenReadCompletedEventHandler(callback);
wc.OpenReadAsync(address);
  关联回调结构和上举例中完全相同最后使用 DownloadStringAsync 思路方法获取个简单串;使用 OpenReadAsync 思路方法获取任意数据无论您决定下载串还是流都属于个人喜好问题在本质上取决于您打算如何使用接收到数据

  另外还要注意WebClient 提供了对可以向远程 URL 执行写入操作思路方法:UploadStringAsync(用于发布串)和 OpenWriteAsync(使用流将任意数据上载到 URL)

  您可以使用 Headers 属性来指定附加标头默认情况下该类并不指定任何标头但应注意您设置某些标头会被 Framework 剥离而改为进行内部管理这些标头包括 Referer、Connection 和 User-AgentContent-Type 标头(如果已设置)会被保留

  在下载资源时WebClient 类会在尝试连接的前透明地使用浏览器缓存Cache如果 XAML 或 XAP 资源不在缓存Cache中则该类将继续执行下载的所以要从 Silverlight 应用下载内容是 Silverlight 运行时和主机浏览器提供给插件内部 API 这 2者共同作用而决定这意味着在 WebClient 掩盖下Silverlight 运行时会和浏览器沙箱进行沟通以查看请求资源是否已存在于缓存Cache中如果不在Silverlight 会依照自己安全策略继续授权请求当数据最终从端点返回时Silverlight 运行时会通过浏览器服务将其缓存Cache在本地并完全遵循当前缓存Cache策略

  Silverlight .Net 命名空间中 WebClient 类和其他 HTTP 类具有许多安全限制特别是 WebClient 类仅支持 HTTP 和 HTTPS 方案(当通过流进行下载时)以及 FILE 方案(当下载纯 XAML 时)跨方案访问被严格禁止因此如果宿主页面是通过 HTTP 下载则无法将 WebClient 指向 HTTPS 资源(反的亦然)WebClient 请求通常可以进入区别浏览器区域内某个 URL但无法从个 Internet 区域移至具有更严格限制个区域Silverlight 目前仅在 Windows 操作系统中支持区域

  最后仅当远程站点通过在其根目录下托管适当 XML 文件来加入时才支持跨域访问另外还要注意跨域访问对 HTTPS-to-HTTPS 方案不起作用

  同个 WebClient 对象无法同时处理多个请求应检查 IsBusy 属性(这是个布尔值)以确定您代码在通过同个 WebClient 例子发出新请求时是否安全如果使用多个 WebClient 对象(可能在区别线程上)则可以同时启动多个下载

  下载仅含 XAML 数据

  让我们看看如何使用 WebClient 下载 XAML 数据并将其集成到可视树中在 Silverlight 2 应用动态下载纯 XAML 数据不定会为您带来您需要编程功能XAML 串必须是纯 XAML没有需要在运行时解析任何引用例如绑定或对样式、资源和事件引用

  XAML 串下载完毕后可使用 XamlReader 类将其转换为 UI 元素然后即可添加到现有文档对象模型中下面代码显示了如何以编程方式从某个 URL 下载 XAML 请注意您需要提供 URL 作为 Uri 对象:

WebClient client = WebClient;
client.DownloadStringCompleted
  DownloadStringCompletedEventHandler(OnDownloadCompleted);
Uri uri = Uri("xaml.ashx", UriKind.Relative);
client.DownloadStringAsync(uri);
  该 URL 可以指向纯 XAML 资源或指向返回 text/xaml 响应端点下面代码将处理下载 XAML 并将其附加到可视树中个占位符上:

void _disibledevent=>  UIElement dom = XamlReader.Load(xaml) as UIElement;
  // Append to the DOM
  Placeholder.Children.Clear;
  Placeholder.Children.Add(dom);
}
  如前所述占位符可以是插件中当前呈现文档对象模型中任何元素请注意UI 元素子元素会形成个集合它们将呈现为个序列这意味着为避免元素的间产生不必要重叠在更新时应首先删除这些元素然后再重新添加

  XAML 序列化(通过 XamlReader 和 XamlWriter 类执行)所基于原则是扩展引用被取消引用而且运行时值通过设计时设置进行保存如果希望下载 XAML 内容并在显示前对其进行自定义(例如通过动态数据绑定)这时该如何办?您无法将绑定嵌入到 XAML 源中但可以在下载 XAML 中定义占位符、通过数据解析检索它们并以编程方式将其设置为您希望任何值但在 Silverlight 2 中下载 XAP 包无疑是更合理解决方案

  使用 XAP

  XAP 包内含整个 Silverlight 应用其用户界面主要由个用户Control控件构成此Control控件实际上只是 XAML 标记和代码容器

  如前所述XAP 包内含指令清单文件所跟踪或多个除下载外处理 XAP 包还会导致两个额外步骤您需要提取主然后例子化用于启动已下载应用入口点类毫无疑问此时您可以在 XAML 中使用绑定、样式、事件以及其他任何需要内容使用 XAP 包时是由 Silverlight 运行时(而不是序列化 API)来处理 XAML 并在随后解析引用这将对编程功能产生巨大影响

  下载和处理 XAP 包还需要许多其他工作而不仅仅是通过串来构建对象模型其中些工作(通常包括内容下载和集提取)可以转给可重复使用 downloader 类(请参见图 3)

在 Silverlight 中管理动态内容交付<img src='/icons/58281dou.gif' />第 1 部分图 3 动态下载 XAP

public partial 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; 
     (shouldDisplay)
    {
       (!IsContentAvailable)
        DownloadContent;
      
        ShowContent;
    }
    
    {
      HideContent;
    }
  }
  private bool IsContentAvailable
  {
     (content != null);
  }
  private void DownloadContent
  {
    Downloader dl = Downloader;
    dl.XapDownloaded
       EventHandler<XapEventArgs>(OnPackageDownload);
    dl.LoadPackage("more.xap", "more.dll", "More.ExtraTab");
  }
  void _disibledevent=>    ShowContent;
  }
  private void HideContent
  {
    this.TabList.Items.Remove(item);
  }
  private void ShowContent
  {
    item = TabItem;
    item.Header = "Extra tab";
    item.Content = content;
    this.TabList.Items.Add(item);
  }
}
  图 3 中代码显示了个基于选项卡举例应用它会在用户首次单击复选框时加载个新选项卡在本例中会下载个新 XAP 而且其用户界面中包含用户Control控件将被插入到新建 TabItem 中隐藏新下载包中内容是个简单客户端操作由于以下两个合理原因重新显示该内容并不需要第 2次往返动作:该内容被缓存Cache在内存中;从中构建该内容包被缓存Cache在浏览器缓存Cache中

Tags:  silverlight2 silverlight是什么 silverlight.2.0 silverlight

延伸阅读

最新评论

发表评论