65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SmartAssembly 进行智能客户端

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (13投票s)

2003年12月25日

8分钟阅读

viewsIcon

170744

downloadIcon

4081

一种使用“拉取模型”保持应用程序程序集最新状态的解决方案。

Sample Image - maximum width is 600 pixels

引言

对于运行信息系统的组织来说,保持桌面应用程序的所有实例与最新版本的可执行文件、库、配置和其他文件同步是一个常见问题。这总是需要大量的资源(人力和时间)。理想情况下,管理员和支持工程师希望一次性将更新的文件部署到中央服务器,然后让更新的文件自动复制到每个桌面安装。SmartAssembly 就是这样一种解决方案,它使用“拉取模型”来实现 .NET 应用程序的更新。

.NET 框架已经为“智能客户端”应用程序提供了支持。您可以在配置文件中配置 <DEPENDENTASSEMBLY> 节点(详情请参阅 MSDN),让运行时下载关联的程序集。但是,存在一些缺点

  1. 配置过于简单,缺乏灵活性。
  2. 下载过程是一个“黑盒”,对终端用户不友好。
  3. 在后期绑定情况下,如果通过其名称(未指定版本、公钥和区域性)加载程序集,运行时将在每次加载同一程序集时打开 HTTP 连接来检查远程程序集。当然,如果您需要频繁加载一些程序集,这将浪费大量时间。

此外,微软还发布了一个名为 Updater 的应用程序块,它也提供了一个“拉取模型”解决方案,用于从中央位置自动下载应用程序更新。但它不是即时工作的。相反,它频繁检查远程清单文件以确定是否需要更新。如果需要,它会启动一个 Updater 进程并关闭用户应用程序以下载更改的文件。下载所有更改的文件后,它会再次启动用户应用程序。

SmartAssembly 旨在满足以下要求

  1. 使下载进度可控、可见和可定制。
  2. 支持断点续传。
  3. 提供支持压缩文件的框架。
  4. 简化部署者的配置工作。
  5. 为部署者提供配置系统的灵活性。
  6. 为开发人员提供可定制性和可扩展性。

工作原理

AppDomainAssembly 中定义了一组 Resolve 事件。这些事件为开发人员提供了自行解析程序集、资源和模块的机会。SmartAssembly 只使用 AssemblyResolve 事件。当该事件触发时,SmartAssembly 搜索配置以查找关联的 codebase URI,然后根据 URI 下载程序集并将其保存到本地,最后加载程序集并将其返回给 AppDomain

使用 SmartAssembly

使用 SmartAssembly 分为两个部分进行描述。首先,需要在应用程序中添加一段代码。然后,编写配置文件并部署应用程序。

编码

顺便说一句,源代码包中附带一个 CHM 文件。您可以参考它了解如何使用 SmartAssembly 的详细信息。

1. 创建 SmartAssemblyManager 实例

SmartAssemblyConfig 用于从 SmartAssembly 配置节创建 SmartAssemblyManager 实例。有三种方法可以实现。

  1. 从应用程序配置文件加载。通过这种方式,返回的 SmartAssemblyManager 实例也是 SmartAssemblyManager.CurrentManager,并且其 CurrentDomain 属性已经设置为 AppDomain.CurrentDomain。相比之下,其他两种方式只是创建一个新的 SmartAssemblyManager 实例
    SmartAssemblyManager sam = 
     ConfigurationSettings.GetConfig(Lightning.SmartAssemblyConfig.SectionName) 
     as SmartAssemblyManager;
  2. SmartAssembly 的独立配置文件加载
    SmartAssemblyManager sam = SmartAssemblyConfig.Create("c:\test.xml");
  3. 从准备好的配置 XmlNode 加载
    // Prepare the configuration XmlNode
    XmlNode section = ...;
    SmartAssemblyManager sam = SmartAssemblyConfig.Create(section);
    if( null != sam ) {
        sam.CurrentDomain = AppDomain.CurrentDomain;
    }

2. 启用 SmartAssembly

要启用 SmartAssembly,您需要将 SmartAssemblyManager 实例的 CurrentDomain 属性设置为 AppDomain

if( null != sam ) {
    sam.CurrentDomain = AppDomain.CurrentDomain;
}

如上所述,如果您从应用程序配置文件创建 SmartAssemblyManager 实例,并且只想处理 AppDomain.CurrentDomain,则可以跳过此步骤。

3. 自定义下载 SmartAssembly 配置文件的例程

SmartAssembly 配置文件可以是独立文件,甚至是数据库记录,因此您可以下载它或从数据库中获取它。SmartAssemblyConfig 提供了一个 static 委托供您执行此操作。

Public static DownloadConfigDelegate DownloadConfigCallback;

4. 自定义解压缩文件的例程

SmartAssembly 在此版本中不提供该功能。但是,它提供了一个定义完善的框架来简化您的工作。您所需要做的就是开发一个 ExtractFileInZipDelegate 函数并处理 SmartAssemblyManager 实例的以下委托,然后遵循压缩文件的配置规则(详见部署部分)。

public ExtractFileInZipDelegate ExtractFileInZipCallback;

5. 自定义其他例程

SmartAssembly 还为 LoadAssemblyLoadlocalAssemblyDownloadFile 等提供了可定制性。

public event LoadAssemblyEventHandler CustomLoadAssembly;
public event LoadAssemblyEventHandler CustomLoadlocalAssembly;

public event SmartAssemblyEventHandler CustomDownloadFile;
public event SmartAssemblyEventHandler CustomDownloadCompleted;
public event DownloadProgressEventHandler CustomDownloading;
public event SmartAssemblyCancelEventHandler BeforeDownload;
public event SmartAssemblyEventHandler AfterDownload;

部署

部署工作主要集中在如何编写配置文件。本节将详细介绍如何配置 SmartAssembly

1. smartAssemblyConfiguration

这是配置的根节点。

<a href="#node_sac"><smartAssemblyConfiguration></a>  
  <a href="#node_sc"><smartConfig></a>
  <a href="#node_cd"><cacheDirectory></a>
  <a href="#node_ns"><netSetting></a>
  <a href="#node_ll"><loadLogic></a>
  <a href="#node_da"><dependentAssembly></a>
    <a href="#node_ai"><assemblyIdentity></a>
    <a href="#node_cb"><codeBase></a>
    <a href="#node_br"><bindingRedirect></a>

子元素

描述

必需

<smartConfig> 指定智能配置文件的设置。 N
<cacheDirectory> 指定缓存目录的设置。 Y
<netSetting> 指定网络连接的参数。 N
<loadLogic> 指定加载程序集的逻辑。 N
<dependentAssembly> 封装每个程序集的绑定策略和程序集位置。 N

2. smartConfig

配置独立的 SmartAssembly 配置文件。如果此节点存在,SmartAssembly 将尝试从该设置加载配置,其他节点将被忽略。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_sc"><smartConfig></a>

Attribute

描述

必需

默认值

href 指定 SmartAssembly 可以找到配置文件的 URL。 N  
filePath 指定 SmartAssembly 保存配置文件的完整文件路径。 N  
tryLocal 如果下载远程文件失败,则尝试本地文件。 N true

3. cacheDirectory

本地缓存目录的设置。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_cd"><cacheDirectory></a>

Attribute

描述

必需

默认值

路径 指定 SmartAssembly 存储程序集的缓存路径。 Y  
type 指定缓存路径的类型。(枚举KeepNewestOnlyKeepAllVersionsKeepAllByHashCode N KeepNewestOnly
packageFilePath 指定 SmartAssembly 存储压缩文件的缓存路径。 N  
shadowCopyCachePath 指定 ShadowCopy 的缓存目录。 N  
shadowCopyExtraDirs 指定 ShadowCopy 的额外目录。 N  

4. netSetting

网络参数的设置。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_ns"><netSetting></a>

Attribute

描述

必需

默认值

agentName 指定 HttpRequest 的代理名称。 N  
bufferSize 指定下载缓冲区的大小。 N 4096
timeout 指定 HttpRequest 的超时值。 N -1

5. loadLogic

加载程序集的逻辑。

<smartAssemblyConfiguration>
  <loadLogic>

Attribute

描述

必需

默认值

notCheckRemoteWhileMatched 指定即使本地文件与请求完全匹配,是否也检查远程文件(程序集)。 N true
downloadNewerOnly 指定是否仅在远程文件比本地文件更新时才进行下载。 N false
tryLatestVersionWhileNotMatch 指定是否自动使用配置文件中配置的最高版本。 N true
smartMatch 指定是否使用“智能匹配”技术。 N true
loadSymbols 指定是否尝试下载与要解析的程序集关联的符号文件。 N false
symbolsFileExtName 指定将用于计算 URI 的符号文件的扩展名。 N pdb
loadMethod 指定加载程序集的方法。(枚举DirectlyViaMemoryStreamShadowCopy N Directly
identifiedByName 指定是否使用弱名称来标识程序集。 N false
workOffline 指定是否在离线模式下工作。 N false
baseHref 指定基本 URI,它将用于计算程序集的 URI。 N  
defaultZipFile 指定默认的压缩文件名,它将用于计算尚未配置的程序集的 URI。 N  

6. dependentAssembly

封装每个程序集的绑定策略和程序集位置。每个程序集使用一个 <dependentAssembly> 元素。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_da"><dependentAssembly></a>
      <a href="#node_ai"><assemblyIdentity></a>
      <a href="#node_cb"><codeBase></a>
      <a href="#node_br"><bindingRedirect></a>

子元素

描述

必需

<assemblyIdentity> 包含有关程序集的标识信息。此元素必须包含在每个 <dependentAssembly> 元素中。 Y
<codeBase> 如果共享程序集未安装在计算机上,则指定运行时在哪里可以找到它。 N
<bindingRedirect> 将一个程序集版本重定向到另一个版本,甚至重定向到另一个程序集。 N
6.1. assemblyIdentity

包含有关程序集的标识信息。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_da"><dependentAssembly></a>
     <a href="#node_ai"><assemblyIdentity></a>

Attribute

描述

必需

默认值

名称 程序集的名称。 Y  
publicKeyToken 一个十六进制值,指定程序集的强名称。 N  
文化 一个字符串,指定程序集的语言和国家/地区。 N  
notCheckRemoteWhileMatched   N true
6.2. codeBase

指定公共语言运行时在哪里可以找到程序集。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_da"><dependentAssembly></a>
    <a href="#node_cb"><codeBase></a>

Attribute

描述

必需

默认值

version 指定代码库适用的程序集版本。程序集版本号的格式为 major.minor.build.revision。版本号每个部分的有效值为 0 到 65535 N  
href 指定运行时可以找到指定版本程序集的 URL。 N  
6.3. bindingRedirect

将一个程序集版本重定向到另一个版本,甚至重定向到另一个程序集。

<a href="#node_sac"><smartAssemblyConfiguration></a>
  <a href="#node_da"><dependentAssembly></a>
      <a href="#node_br"><bindingRedirect></a>

Attribute

描述

必需

默认值

oldVersion

指定最初请求的程序集版本。有三种可能的格式

  • 单个n.n.n.n
  • 范围n.n.n.n - n.n.n.nn.n.* (与 n.n.0.0 - n.n.65535.65535 相同)
  • 集合n.n.n.n; n.n.n.n; n.n.n.n; ...
N  
newVersion

指定要使用的程序集版本或新程序集,而不是最初请求的版本。新程序集的格式应如下所示

NewAsm, Version=1.0.0.0, Culture=en-us, PublicKeyToken=

N  

一个完整的例子

<configuration>
  <!-- Declaring custom config  section parsing class -->
  <configSections>
    <section name="smartAssemblyConfiguration" 
      type="Lightning.SmartAssemblyConfig, SmartAssembly"/>
  </configSections>
  
  <smartAssemblyConfiguration>
    <!--smartConfig temp="%ComAppData%\Assembly\config.xml"
           href="https:///Assembly/Test.xml" /-->
    
    <cacheDirectory path="%ComAppData%\Assembly\Origin"
            type="KeepAllVersions"
            packageFilePath="%ComAppData%\Assembly\ZipFiles" />
    <netSetting agentName="Smart Assemlbly Manager"
          bufferSize="8182" timeout="-1"
          proxyMode="" />
    <loadLogic notCheckRemoteWhileMatched="true"
          downloadNewerOnly="true"
          tryLatestVersionWhileNotMatch="true"
          smartMatch="true"
          loadSymbols="true"
          loadMethod="ShadowCopy"
          identifiedByName="true"
          workOffline="false"
          baseHref="https:///Assembly/" />

    <dependentAssembly>
      <assemblyIdentity name="MainControl" publicKeyToken="" culture="" />
      <codeBase version="" href="old/MainControl.dll"/>
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="SubControl1"
                publicKeyToken="a9061ec0e85bbecf"
                culture="" />
      <codeBase version="0.0.1.0" href="old/SubControl1.dll"/>
      <codeBase version="2.1.0.0" href="new/SubControl1.dll"/>
      <bindingRedirect oldVersion="0.0.0.1; 0.0.0.2" newVersion="0.0.1.0" />
      <bindingRedirect oldVersion="1.0.*" newVersion="2.1.0.0" />
      <bindingRedirect oldVersion="1.1.0.0 - 2.0.0.0" newVersion="2.1.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="SubControl2" publicKeyToken="" culture="" />
      <codeBase version="" href="old/SubControl2.dll"/>
    </dependentAssembly>
    
    <dependentAssembly>
      <assemblyIdentity name="MainControl.resource" publicKeyToken="" culture="" />
      <bindingRedirect oldVersion="*" 
        newVersion="MainControl.resource, Version=, Culture=, PublicKeyToken=" />
    </dependentAssembly>
    </smartAssemblyConfiguration>
</configuration>

关于演示

演示解决方案中有三个项目

SmartAssembly SmartAssembly 库。
测试 可以独立执行或由 IE 加载的演示应用程序(详见 readme.txt)。
TestControl 将被“SmartAssembly”的演示程序集。

关注点

部署有一些技巧,例如

  • 决定将缓存目录设置到何处,是 AppBaseDirAppData 还是 ComAppData
  • 如果使用压缩文件,如何打包程序集,作为应用程序、作为包还是其他策略?

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.