出自
.NET Client Applications: .NET Application Updater Component
http://windowsforms.net/articles/appupdater.aspx
http://windowsforms.net/downloads/GDN/dotnetupdater.zip
Using The Updater Application Block
http://www.theserverside.net/tt/articles/showarticle.tss?id=UpdateAppBlock
TaskVision 解决方案概述:设计与实现
http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/softwaredev/SCdnwinformswnftaskvision.mspx?mfr=true
.net的rich client自动升级方案
http://yyanghhong.cnblogs.com/archive/2004/11/08/61409.aspx
如何得知是否需要更新:
1.比较文件的时间戳,缺陷在于
如果管理员正在更新服务器上的程序,同时有个客户正在下载更新之前的版本,那么这个客户的计算
机上就会既存在更新之前的一些文件,也存在更新之后新版本的一些文件。
2.在服务器上放一个xml文件,来描述应用程序中所有assembly的版本,client会和本地的程序比较并决定
是否下载
3.server 端保存用户信息, client调用一个web service来决定是否需要更新.
如何下载:
下载使用HTTP-DAV来完成。DAV 是一种扩展的HTTP,提供遍历目录和文件的功能。
下载过程中可能会出现以下问题:更新文件所属的服务器可能会崩溃,客户端机器也可能崩溃,或者因为某种原因
用户关闭了应用程序,这些都会导致下载的终止。使用系统服务,即便应用程序自身没有在运行,更新下载也会继续。
Windows XP有一种称之为BITS的内建的下载服务,是Windows XP用来对Windows自身进行下载更新的。
参阅http://msdn.microsoft.com/library/en-us/dnwxp/html/WinXP_BITS.asp。
在.NET应用程序更新组件中没有使用这种服务,因此可用在不支持系统服务的系统(Windows 9x,Mono)中使用。
.NET Application Updater component把download 和 update 过程分为几个独立,可重复执行的的过程,每个过程的
执行结果都记录在client 程序所在的路径下的一个文件中,如果某个步骤失败,.NET Application Updater component
会重试,实在不行就报错退出.
如何执行Update
该过程的难点在于有可能会更新正在运行的程序.
最简单的方案是使用一个独立的进程来执行更新,Update进程会shutdown Application进程,然后执行update,最后重启
Application.但是这个解决方案有如下的问题:
1. Update 进程由App进程产生, Update进程kill app进程,当APP运行在Job模式下, Update进程也会被终止.
2. 执行更新的模块也需要更新.
最终的方案使用了一个小的"诡计",避开直接更新应用程序本身,而是新建一个目录然后下载新版本的引用程序,下载完成
后使用新版本的可执行文件启动应用程序,并且删除老版本程序,由于要有选择地启动某个版本的程序,需要一个引子程序
AppStart,用它来作为应用程序的入口.整个应用程序的目录结构如下:
Program File
My App
AppStart.exe
AppStart.config
V1 Folder
MyApp.exe
V2 Folder
MyApp.exe
AppStart.exe会根据AppStart.config来决定启动那个版本的exe
<Config>
<AppFolderName>V1 Folder</AppFolderName>
<AppExeName>MyApp.exe</AppExeName>
<AppLaunchMode>appdomain</AppLaunchMode>
</Config>
更新程序可以通过修改<AppFolderName>来决定执行那个版本的app.
<AppLaunchMode>会使AppStart.exe和MyApp.exe运行在同一进程的不同的AppDomain中,
Appstart启动MyApp后就sleep,等待MyApp结束.通常情况下MyApp结束后,AppStart也会shutdown,
但如果MyApp结束时返回一个特有的返回值,AppStart会重新MyApp.
.Net Updater Component
只有一个文件,AppUpdater.dll.
主要属性:
AutoFileLoad: 用户实现按需下载,当CLR找不到一个dll时,会raise AppDomain.AssemblyResolve 事件,
.Net Updater Component会hook这个event,进行下载,更新.
ChangeDetectionMode: 采用何种方式检查更新,一般使用ServerManifestCheck.
ShowDefatultUI: 是否使用.Net Updater Component自带的UI提示用户,也可以hook .Net Updater Component的
有关事件如OnUpdateComplete来弹出自定义的UI.
AppUpdater obj必须生成在app的主UI线程中,否则不能显示UI,也不能给UI线程发Event显示UI.
UpdateUrl: 在何处查找Updata信息,如果使用了ServerManifestCheck Mode,UpdateUrl可指定为:
http://yourWebserver/SampleApp_ServerSetup/UpdateVersion.xml.
UpdateVersion.xml的内容为:
<VersionConfig>
<AvailableVersion>1.0.0.0</AvailableVersion>
<ApplicationUrl>http://localhost/SampleApp_ServerSetup/1.0.0.0/</ApplicationUrl>
</VersionConfig>
用来描述需要下载文件所在的目录
Downloader.DownloadRetryAttempts : 下载重试次数
Downloader.SecondsBeteweenDownloadRety :
Downloader.UpdateRetryAttempts :
Downloader.ValidateAssemblies : 是否进行了Strong Name检查后才进行下载.
Poller.AutoStart : 是否在程序启动后自动检测
Poller.DownloadOnDetection : 是否在检测到更新后自动下载
Poller.InitialPollInterval : 程序启动后多长时间开始检测.
Poller.PollInterval
使用AppUpdater.dll
1.Create 一个带Form的Project,把 .Net Updater Component揪到From上,并配置
2.Client端
Build出一个AssemblyVersion为1.0.0.0的SampleApp.exe
c:\ClientSetup\Appstart.config
\AppStart.exe
\1.0.0.0\
\SampleApp.exe
Appstart.config的内容为
<Config>
<AppFolderName>1.0.0.0</AppFolderName>
<AppExeName>SampleApp.exe</AppExeName>
</Config>
3.Server端
Build出一个AssemblyVersion为2.0.0.0的SampleApp.exe
Create VD ServerSetup
ServerSetup\UpdateVersion.xml
\2.0.0.0\
UpdateVersion.xml的内容为:
<VersionConfig>
<AvailableVersion>3.0.0.0</AvailableVersion>
<ApplicationUrl>http://localhost/ServerSetup/2.0.0.0/</ApplicationUrl>
</VersionConfig>
配置IIS,由于.net updater component使用了HTTP-DAV协议,所以在vd ServerSetup上要打开
"Directory Browsing"选项.
4.把玩
在Client端运行SampleApp.exe, 可看到提示是否需要更新…
5.深入讨论按需下载.
把AutoFileLoad设为true可实现按需下载,下载需要时间,此时applicatin 会完全失去相应
6.安全
1.拦截数据包,并篡改
解药:使用HTTPS,做法很简单只要使用HTTPS URL代替 HTTP URL
但价格昂贵,HTTPS会加密被下载的所有文件.
2.服务器上的文件被篡改.
解药:使用strong name..net updater component会比较已安装的组件的public key和要下载的组件
的public key,只有被相同private key标记的assembly才会由相同的public key, 所以如果一致,
就认为要下载的文件是合法的.
但在现实中,Application的各个组件常常是由不同的private key标记的,比如有这样的application,
由一个exe和一个第3方控件组成.此时,构造一个名为AppUpdateKeys.dll的assembly,
public class KeyList
{
public static byte[][] Keys;
public static string[] ExceptionList;
static KeyList()
{
//Add the list of public keys your app uses here
Keys = new byte[][]
{
new byte[] { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 95, 81, 246, 90, 218, 186, 162, 97, 166, 49, 31, 81, 219, 192, 9, 180, 14, 174, 24, 158, 138, 225, 14, 38, 226, 192, 31, 171, 74, 47, 210, 255, 104, 31, 90, 175, 172, 246, 149, 141, 132, 248, 25, 166, 64, 102, 240, 89, 239, 22, 97, 54, 233, 217, 7, 155, 23, 87, 172, 111, 39, 104, 48, 97, 200, 50, 155, 32, 37, 42, 212, 167, 201, 220, 50, 119, 84, 201, 191, 19, 164, 227, 94, 9, 44, 79, 115, 18, 25, 236, 73, 169, 16, 14, 84, 241, 175, 110, 112, 223, 214, 81, 111, 220, 222, 16, 224, 208, 204, 65, 108, 207, 171, 88, 52, 149, 212, 147, 62, 9, 112, 118, 105, 25, 24, 161, 235, 213 }
};
//Add the list of files that don’t need to be signed, but are allowed to be downloaded even if not signed.
//PDB files would be a good example of this type of file.
ExceptionList = new string[] {"simpleform.dll", "simpleform.pdb"};
}
}
AppUpdateKeys.dll包含了应用程序用到的所有assembly的public key,然后用应用程序的private key
来标记AppUpdateKeys.dll,下载时updater会首先对比AppUpdateKeys.dll的public key和应用程序的publickey,
如果通过验证,就下载AppUpdateKeys.dll,并提取AppUpdateKeys.dll中所有的public key,包含这些 public key
的Assembly就被认为是合法的.同时AppUpdateKeys.dll和可以定义一个ExceptionList, list中的文件可以不进行
验证.
实际应用 Terrarium:
Terrarium hook .NET Application Updater component 的 OnCheckForUpdate event,并在event handler中调用web
service来检查更新.OnCheckForUpdate是由poller 线程引发的,所以调用web service不会lock UI 线程.
Terrarium hook .NET Application Updater component 的 OnUpdateComplete event 使用自定义的UI, OnUpdateComplete
由UI 线程引发,所以可以直接在OnUpdateComplete的event handler中使用UI.
附录:
.Net 平台上的其他自动升级方案
Updater Application Block version 2.0
http://www.microsoft.com/downloads/details.aspx?FamilyID=c6c09314-e222-4af2-9395-1e0bd7060786&DisplayLang=en
Using the Updater Application Block
http://www.theserverside.net/tt/articles/showarticle.tss?id=UpdateAppBlock
DotNet No-Touch Deployment (NTD)
http://www.dotnet-online.de/web/notouch/
Clickonce
http://www.windowsforms.net/WhidbeyFeatures/default.aspx?PageID=2&ItemID=19&Cat=Runtime&tabindex=5