通用系统自动升级程序的简单实现
开发背景:在平时开发C/S系统时,大家都清楚C/S系统的最大弱点就是不利于维护,当客户端程序更新时不得不到每个用户的机子上去部署。虽然微软的Smart Client技术使得传统的C/S系统更加利维护,但公司现在还不打算采用,而Updater Application Block组件的配置和使用相以地麻烦,所以我们选择采用传统的自动更新的程序。
自动更新的步骤就是客户端检查服务器端的版本号是否比本地的高,如果高于本地版本,就向服务器请求下载文件。在这里我们服务器端部署的升级文件是任何人都可以下载的。可能与某些情况不同。从上面的描述可以看出,其实所有系统自动升级的步骤都是类似的,所以做一个通用的自动升级程序就一劳逸了。
解决方案如下图:
类图如下:
先让我们来看下升级文件的配置:
服务器端(SystemUpdateXMLFile.xml)
<UpdateConfig>
<SystemName Name="Archives" Description="档案系统">
<Version>2.0</Version><!--当前版本号码-->
<NewFilePath>UpDateFile/Archives</NewFilePath><!--更新文件所在路径-->
<Level>1</Level><!--更新等级 1表示强制更新-->
</SystemName>
<SystemName Name="FinishArchives" Description="成品档案系统">
<Version>2.0</Version><!--当前版本号码-->
<NewFilePath>UpDateFile</NewFilePath><!--文件所在路径-->
<Level>1</Level><!--更新等级 1表示强制更新-->
</SystemName>
</UpdateConfig>
客户端:(SystemUpdateXMLFile.xml)
<UpdateConfig>
<SystemName Name="FinishArchives" Description="成品档案系统">
<Version>1.0</Version><!--当前版本号码-->
<AutoUpdate>true</AutoUpdate><!--更新等级 1表示强制更新-->
<MainAppPath>MainFrom.exe</MainAppPath><!--主程序路径-->
</SystemName>
</UpdateConfig>
App.Config
<configSections>
<section name="AutoUpdateIco" type="AutoUpdate.IcoFactory.CustomSectionHandler, AutoUpdate.IcoFactory"/>
</configSections>
<appSettings>
<add key="UpdateWebService" value="http://localhost/AutoUpdate.WebService/VersionInfoService.asmx"></add>
</appSettings>
<AutoUpdateIco>
<add key="ClientAssembly" value="AutoUpdate.ClientComponent.dll" /><!--实现客户端服务的程序集名称-->
<add key="ClientComponent" value="AutoUpdate.ClientComponent.XmlFileComponent" /><!--实现客户端服务的类名-->
</AutoUpdateIco>
</configuration>
不难看出每一个系统都需要在服务器端的XML文件中配置类似的信息,也许你觉得XML文件储蓄信息不太好,想把系统的信息放到数据库里,是不是我们的程序就要重写呢?不是的,在设计这个系统时我釆用了依赖注入的方法 由CreateComponentFactory类负责装配相应的服务, CreateComponentFactory类的部份代码如下:
/// <summary>
/// 得到客户端组件
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static IClientVersionInfo CreateClientObject(string path)
{
object objType = new object();
string assemblyPath = string.Empty;
string serverComponent = string.Empty;
GetClientIcoConfig(out assemblyPath,out serverComponent);
assemblyPath = path + "\\" + assemblyPath;
try
{
objType = Assembly.LoadFile(assemblyPath).CreateInstance(serverComponent,false);//反射创建
}
catch(System.Exception e)
{
throw e;
}
return (IClientVersionInfo) objType;
}
#endregion
#region 得到服务器端组件
/// <summary>
/// 得到服务器端组件
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static IServerVersionInfo CreateServerObject(string path)
{
object objType = new object();
string assemblyPath = string.Empty;
string serverComponent = string.Empty;
GetServerIcoConfig(out assemblyPath,out serverComponent);
assemblyPath = path +"\\"+ assemblyPath;
try
{
System.Reflection.Assembly a = Assembly.LoadFile(assemblyPath);
objType = Assembly.LoadFile(assemblyPath).CreateInstance(serverComponent);//反射创建
}
catch(System.Exception E)
{
throw E;
}
return (IServerVersionInfo) objType;
}
#endregion
在服务器端如需要将系统版本信息保存到数据库,只需要新开发一个继承自IServerVersionInfo接口的组件,并修改相应的XML文件就可以了。
<section name="AutoUpdateIco" type="AutoUpdate.IcoFactory.CustomSectionHandler, AutoUpdate.IcoFactory"/>
</configSections>
<AutoUpdateIco>
<add key="ServerAssembly" value="AutoUpdate.ServerComponent.dll" /><!--实现服务的程序集名-->
<add key="ServerComponent" value="AutoUpdate.ServerComponent.XmlFileComponent" /><!--实现服务的类名-->
</AutoUpdateIco>
在服务器端,采用了缓存,以提高性能。
2 public ServerModel GetSerVersionInfo(string sysname)
3 {
4 object objType = ObjectCache.GetCache(sysname);//从缓存读取
5 string path = Server.MapPath("");
6
7 ObjectInfo objinfo=new ObjectInfo(sysname,path);
8
9 IServerVersionInfo serv = GetIServerVersionInfo(sysname);
10
11 ServerModel model = serv.GetSerVersionInfo(objinfo);
12 return model;
13 }
14
15 [WebMethod(Description="要更新的文件列表")]
16 public string[] NewFileFiles(string sysname)
17 {
18 string path = Server.MapPath("");
19
20 ObjectInfo objinfo=new ObjectInfo(sysname,path);
21
22 IServerVersionInfo serv = GetIServerVersionInfo(sysname);
23
24 return serv.NewFileFiles(objinfo);
25 }
26
27 private IServerVersionInfo GetIServerVersionInfo(string sysname)
28 {
29 object objType = ObjectCache.GetCache(sysname);//从缓存读取
30 if (objType == null)
31 {
32 try
33 {
34 IServerVersionInfo serv = new ServerComponent.XmlFileComponent();
35
36 ObjectCache.SetCache(sysname, serv);// 写入缓存
37 }
38 catch
39 {}
40 }
41 return (IServerVersionInfo)objType;
42 }
此版本没有考虑到系统内部单个文件的版本更新,这是一个不足的地方,但在目前的系统中已经够用了,等以后有时间再来完善。