微软公司提供的Microsoft Application Block为开发具有智能更新功能的.NET应用提供了极大的便利。在HIS Demo中我们重用并扩展了Updater Application Block (UAB)等应用程序模块,实现了符合HIS应用实际需求的自动更新等功能。
使用UAB可以实现对.NET应用智能更新支持,UAB为应用提供了下载,验证和后置处理机制。通过UAB提供的接口,我们可以轻易对UAB根据自己需要进行扩展。在HIS Demo中,我们使用BITS下载机制,保证系统的运作效率。UAB的工作流程如下图所示:
UAB主要有四个模块组成Updater, Downloader, Validate以及Post Processor组成。Updater负责整个更新工作的管理;Downloader实现文件的下载,UAB中采用BITS (Background Intelligence Transfer Service)作为Downloader,UAB提供了IDownloader 接口,实现这个接口,开发者可以开发基于任意协议的下载器;Validator完成对下载文件的校验,UAB中提供KeyValidator和RSAValidator两个类,分别来实现对对称和非对称加密文件的校验;Post Processor则提供完成文件更新后需要进行的各种操作。
Q 如何在应用中实现基本的自动更新功能?
HIS Demo中将自动更新的主要功能封装在SelfUpdater类中(源文件HISDEMO \HISCLINIC \SelfUpdater.cs)
在SelfUpdater类中通过InitUpdater()方法对Updater进行初始化,主要工作包括实例化ApplicationUpdateManager,为更新过程中主要的事件UpdaterAvailable和FilesValidated等事件指定事件处理器
/***********************************************************
private void InitUpdater()
{
updater=new ApplicationUpdateManager();
updater.UpdateAvailable += new UpdaterActionEventHandler(updater_UpdateAvailable);
updater.FilesValidated += new UpdaterActionEventHandler(updater_FilesValidated);
}
/***********************************************************
UpdaterAvailable事件当UAB发现服务器上有新的应用版本时发生,这时通常会询问用户是否要需要更新,如果用户选择需要则开始下载
/***********************************************************
///
///当判定存在更新文件时相应的事件方法
///
///
///
private void updater_UpdateAvailable(object sender, UpdaterActionEventArgs e)
{
// Show a message allowing the user to determine if they would like to download the update
// and perform the upgrade
string message = String.Format(
"更新提示:现在服务器上的最新版本是 {0} , 需要更新吗?",
e.ServerInformation.AvailableVersion ) ;
DialogResult dialog ;
if(MsgBoxOwner!=null)
dialog = MessageBox.Show(MsgBoxOwner, message, "更新提示",
MessageBoxButtons.YesNo );
else
dialog = MessageBox.Show( message, "更新提示", MessageBoxButtons.YesNo );
UpdaterArgs args=new UpdaterArgs();
// The user has indicated they don't want to upgrade
if( DialogResult.No == dialog )
{
// stop the updater for this app
updater.StopUpdater( e.ApplicationName );
args.IsRunning=false;
}
Else
{
args.IsRunning=true;
}
//
if(UpdaterStateCallBack!=null)
UpdaterStateCallBack(this,args);
}
/***********************************************************
FilesValidated事件当更新文件成功下载并通过校验后发生,这时时通常会询问用户是否要需要运新更新后的程序,如果用户选择需要是则需要停止当前应用并启动更新后的应用
/***********************************************************
///
/// 当更新文件下载完毕时相应的事件方法
///
///
///
private void updater_FilesValidated(object sender, UpdaterActionEventArgs e)
{
// Ask user if they want to use the new version of the application
DialogResult dialog = MessageBox.Show(
"需要打开新的应用程序吗?",
"打开新版本?", MessageBoxButtons.YesNo );
if( DialogResult.Yes == dialog )
{
// Load this applications configuration file to read the
// UAB information and obtain the basedir
XmlDocument doc = new XmlDocument();
doc.Load( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile );
string baseDir = doc.SelectSingleNode(
"configuration/appUpdater/UpdaterConfiguration/application/client/baseDir"
).InnerText;
// Figure out the path to AppStart.exe which we will chain to
string newDir = Path.Combine( baseDir, "AppStart.exe" );
// Launch AppStart.exe which will launch the new version
ProcessStartInfo process = new ProcessStartInfo( newDir );
process.WorkingDirectory = Path.Combine( newDir ,
e.ServerInformation.AvailableVersion );
Process.Start( process );
StopUpdate();
Environment.Exit( 0 );
}
}
/**********************************************************
使用自动更新是在主表单中实例化SelfUpdater类即可。
/***********************************************************
public frmMainForm()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//Init update obeject
updater=new SelfUpdater();
……
}
/***********************************************************
Q 如何产生和配置清单文件(Manifest.xml)?
清单文件在整个更新过程非常重要。在更新的过程中这个清单会被Downloader从服务器上下载到本地,由Updater进行解析并判断是否有更新。如果有更新,Downloader会根据清单的内容,从服务器上下载相应的文件,Validator会根据清单中的签名对清单进行校验。下面是清单文件的例子,可以看出清单中的信息包括清单本身的签名,可用的应用版本号和位置,文件列表和签名,后处理器的名称等。
注意:如果采用了RSA加密签名,则不可以手动改变此清单。此清单应由相应工具产生并用私有密钥进行签名。
.......
清单可用采用UAB自带的工具ManifestUtility.exe产生,如下图所示:
Q 如何产生和配置App.Config文件?
App.Config文件决定了在客户运行的应用版本和位置,其内容如下。其中最关键的appFolderName节点,此路径应为程序的安装路径,此文件应该在客户端初次安装时生成并置于应用的根目录下。
Q 如何产生和配置HISDemo.exe.config文件?
HISDemo.exe.config文件主要说明了应用使用UAB的情况和配置,对于使用RSA加密签名的文件,公钥存于此文件中。另外,在本应用中Sql的连接字符串也存于此文件中。如Sql服务器配置有改动,只需要改写此文件中的相应信息即可。
Q 如何将安装路径写入配置文件?
为了能使UAB正常的工作,在配置文件HISClinic.exe.config中需要指明程序安装的路径。由于客户端可能安装在任意的路径下,为此在应用的文件安装或下载以后需要再将安装路径写入配置文件,确保应用的正常工作。
在应用程序的文件完成拷贝和下载后,需要运行如下代码,实现下列任务:通过Reflection.Assembly取得当前运行路径以及更改HISClinic.exe.config配置
参考代码: HISClinic\HISDemo\PostProcessor\Processor.cs
/***********************************************************
public class Processor:IPostProcessor
{
public Processor()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
///
/// 实现IPostprocessor.Run接口方法
/// 更改下载程序配置信息
///
public void Run()
{
String p=Path.GetDirectoryName
(System.Reflection.Assembly.GetExecutingAssembly().Location);
DirectoryInfo dir=new DirectoryInfo(p);
Config.ConfigFile config=new
Config.ConfigFile(Path.Combine(p,@"HISClinic.exe.config"));
config.ChangePath("HISClinic",dir.Parent.FullName);
}
public void Dispose(){}
}
/***********************************************************
Q 如何设定更新检测的时间?
应用程序如需要设定更新检测时间,可以通过设置HISClinic.exe.config的polling节点属性以及设定UAB的UpdaterConfiguration.Instance来实现
参考代码: HISClinic\HISDemo\HIClinic\SelfUpdater.CS;
HISClinic\HISDemo\ChangePath\Config.CS;
/***********************************************************
///
/// 设置Polling间隔
///
public int Interval
{
set
{
SavePollingIntoConfigFile(value);
}
get
{
return GetPollingInterval();
}
}
///
/// 保存更新间隔,单位(秒)
///
///
private void SavePollingIntoConfigFile(int interval)
{
Config.ConfigFile configfile=new
Config.ConfigFile(System.Reflection.Assembly.
GetExecutingAssembly().Location+".config");
//修改配置文件
configfile.UpdateInterval=interval;
//修改UAB实例
UpdaterConfiguration.Instance.Polling.Value=interval.ToString();
UpdaterConfiguration.Instance.Polling.Type=PollingType.Seconds;
}
///
/// 获取更新间隔,单位(秒)
///
///
private int GetPollingInterval()
{
Config.ConfigFile configfile=new
Config.ConfigFile(System.Reflection.Assembly.GetExecutingAssembly().Loca
tion+".config");
return configfile.UpdateInterval;
}
/***********************************************************
Q 如何实现强制的手动即时更新?
应用程序如果需要通过界面控制实现强制的手动即时更新,可以通过以下方式实现。首先调用ApplicationUpdateManager.StopUpdater()停止更新,然后重新实例化ApplicationUpdateManager,并通过调用StartUpdater()实现更新
参考代码: HISClinic\HISDemo\HIClinic\selfUpdater.CS
/***********************************************************
///
/// 重新开始更新
///
public void ReStartUpdate()
{
updater=null;
InitUpdater();
updater.StartUpdater();
}
/***********************************************************
Q 如何设定更新日志路径以及设定是否需要保留更新日志?
默认情况下,UAB会将更新日志存放在应用安装的根目录下,并且每次运行运用都会产生一个新的日志。这种机制会在客户端留下大量的日志文件。如果需要设定更新日志路径以及设定是否需要保留更新日志,需要更改UAB配置文件和对应实例以及EMAB配置文件
参考代码: HISClinic\HISDemo\HIClinic\SelfUpdater.CS;
HISClinic\HISDemo\ChangePath\Config.CS;
/***********************************************************
///
/// 设置日志路径
///
///
public void SetLogPath(string path)
{
XmlDocument doc=new XmlDocument();
doc.Load(configfilepath);
XmlNodeList nodes=doc.GetElementsByTagName("logListener");
if(path.Length>0)
{//设置UAB日志标志
XmlNode node=null;
if(nodes.Count>0) node=nodes[0];
else
{
node=doc.CreateElement("logListener");
XmlAttribute attr=doc.CreateAttribute("logPath");
node.Attributes.Append(attr);
doc.SelectSingleNode("configuration/appUpdater/UpdaterConfigurat
ion").AppendChild(node);
}
node.Attributes["logPath"].Value=path;
}
else
{//设置EMAB日志标志
XmlNode node=doc.SelectSingleNode
("configuration/appUpdater/UpdaterConfiguration/logListener");
if(node!=null)
node.ParentNode.RemoveChild(node);
}
SetEMABLogPulish(path.Length>0,doc);
doc.Save(configfilepath);
}
/***********************************************************
Q 如何实现使用任意协议(http, ftp…)进行下载?
UAB采用Windows自带的BITS服务进行文件的下载,如需要采用任意协议或是自定义的下载器进行下载,开发自定义的下载器,并实现IDownloader接口即可
如何删除客户端操作系统上不必要的较早版本的文件备份
默认情况下UAB会保留较早版本的文件备份,可以通过实现IPostprocessor接口,开发简单代码,在应用更新成功后,对不必要文件进行删除。
Q 如何在应用安装的同时自动的导入数据库?
将要安装的数据库文件.mdf拷贝到[数据库安装路径]通过OSQL命令调用如下的T-SQL 脚本。
EXECUTE sp_attach_db @dbname = N'
@filename1 = N'
@filename2 = N'
GO
文件的拷贝和OSQL命令的调用可以通过安装程序进行,从而实现数据库的自动安装。
0 评论:
发表评论