普遍的做法是给Xap包、配置文件增加版本号控制。
Xap包、配置文件的版本可以通过配置文件记录,但是需要在项目更新时,更新此文件,对于规模比较大的项目(Xap包比较多) ,升级、维护也存在困难。如果配置文件的版本也放到版本控制的文件中,维护工作量会很大。鉴于此,我们可以采取以下方案:
1.Xap包、配置文件版本文件由程序自动更新。
以Asp.net为例:
可以在Global.asax 中增加监测Xap文件修改记录,如果有修改,则自动更新版本记录文件或更新记录文件版本的变量,代码如下:
string xapFilePath =Server.MapPath("Clientbin"); if (System.IO.Directory.Exists(xapFilePath)) { System.IO.FileSystemWatcher xapFileWatcher = new System.IO.FileSystemWatcher(xapFilePath, "*.xap"); Application["XapFileWatcher"] = xapFileWatcher; //设置监测的文件修改类型 xapFileWatcher.NotifyFilter = System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.CreationTime | System.IO.NotifyFilters.Size; xapFileWatcher.Created += xapFileWatcher_Changed; xapFileWatcher.Changed += xapFileWatcher_Changed; xapFileWatcher.Deleted += xapFileWatcher_Changed; xapFileWatcher.Renamed += xapFileWatcher_Changed; xapFileWatcher.EnableRaisingEvents = true; }
/// <summary> /// 检测到文件更新,更新文件版本 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void xapFileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) { GetFileInfo(); }
private void GetFileInfo() { List<String> fileList = new List<string>(); string serverPath = GetFilePath(); if (System.IO.Directory.Exists(serverPath)) { System.IO.DirectoryInfo ClientBinInfo = new System.IO.DirectoryInfo(serverPath); foreach (System.IO.FileInfo xapFile in ClientBinInfo.GetFiles("*.xap")) { string fileName = xapFile.Name; //我们这里采用文件修改时间作为版本标识 string modifyTime = xapFile.LastWriteTime.ToString("yyyyMMddHHmmss"); fileList.Add(string.Format("{0},{1}", fileName, modifyTime)); } } string file = System.IO.Path.Combine(serverPath, "XapVar.xml"); SaveVerToFile(fileList, file); }
/// <summary> /// 序列化,保存 /// </summary> /// <param name="aObject"></param> /// <param name="fileName"></param> /// <returns></returns> private void SaveVerToFile(object aObject, string fileName) { using (System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.Create)) { var serializer = new System.Runtime.Serialization.DataContractSerializer(aObject.GetType()); serializer.WriteObject(fs, aObject); fs.Close(); } }
这种方式可以做到自动监测,自动更新,不需要手工参与。版本更新可以采用上面的更新文件的方式(记住给目标目录开通读写权限),也可以通过Silverlight的InitParameter传递给Silverlight端控制。
至于Silverlight端接收到文件版本,可以通过在Uri后加版本参数的方式,控制浏览器使用更新后的Xap或配置文件。例如:
TextApp.xap?201301231551
增加参数的方式可以在各模块单独加,也可以封装一个公共处理模块负责读取文件、更新版本。还有一种处理方式,可以一次性解决版本问题,即重写WebRequest创建者,代码如下:
/// <summary> /// 创建WebRequest,并根据版本号更新请求Url /// </summary> internal class BrowserHttpWebRequestCreator : System.Net.IWebRequestCreate { string mSysVar = "0"; public BrowserHttpWebRequestCreator(string sysVar) { mSysVar = sysVar; } public System.Net.WebRequest Create(Uri uri) { if (uri != null) { string uriStr = uri.OriginalString; if (uriStr.IndexOf("?") == -1) { uriStr = uriStr + string.Format("?{0}", mSysVar); uri = new Uri(uriStr, UriKind.RelativeOrAbsolute); } } return System.Net.Browser.WebRequestCreator.BrowserHttp.Create(uri); } }
使用下面的代码指定Silverlight使用我们的Creator:
BrowserHttpWebRequestCreator browserHttpWebRequestCreator = new IMG.Startup.BrowserHttpWebRequestCreator(版本号); System.Net.WebRequest.RegisterPrefix("http://", browserHttpWebRequestCreator); System.Net.WebRequest.RegisterPrefix("https://", browserHttpWebRequestCreator);
对于已经开发完毕的系统,要增加版本控制能力,也可以采用这种方式。只需要在App中增加这部分处理就可以,不需要修改现有模块。
ps:上面的代码是版本统一控制,如果针对不同文件控制,修改相应逻辑即可。