开发背景:在平时开发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 }
此版本没有考虑到系统内部单个文件的版本更新,这是一个不足的地方,但在目前的系统中已经够用了,等以后有时间再来完善。