ClickOnce DIY全自动更新下载升级的自我实现

  SmartClient概念近来比较热,但在微软提出这个名词以前已经有大量的软件在这么做了,一方面是简化客户端的部署,一方面是提供自动升级的功能;对于传统的WinForm应用来讲,确实是可以降低维护成本的一个不错的解决方案;

  微软在推出SmartClient概念时,推出了相关的updater的Application Block,做的也蛮不错,但作者前段还是根据软件特性自己写了一个很简单的实现,大家也大概能了解一下原理:

  笔者的简化版自动升级管理器只需要四步走:

  1.一个负责查找和下载新版本的本地类

  2.本地配置文件中(或在代码中硬编码?不太好吧),指向更新服务器的URL

  3.服务器上一个标识版本号和新文件URL的配置文件

  4.调用示例

  1.版本管理类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.Xml;

  using System.Net;

  using System.IO;

  using System.Windows.Forms;

  namespace Survey

  {

  class VersionAgent

  {

  public static bool CheckNetwork()

  {

  HttpWebRequest request;

  try

  {

  request = (HttpWebRequest)WebRequest.Create(Pub.GetSetting("UpdateUrl") );//从本地配置文件获取的网络中配置文件的URL

  request.Proxy = WebProxy.GetDefaultProxy();

  request.GetResponse();//如果可以获得响应,说明网络没问题

  }

  catch (Exception e)

  {

  Pub.logError(e);

  return false;

  }

  return true;

  }

  public static bool CheckUpdate()

  {

  XmlDocument doc = loadXMLDocument(Pub.GetSetting("UpdateUrl"));

  Sys.UpdateUrl = GetValue(doc, "DownloadURL").Trim();//将来会用这个URL自动下载

  Sys.UpdatePage = GetValue(doc, "DownloadPage").Trim();//如自动下载失败,会提供到这个页面手工下载

  string warningRate = GetValue(doc, "WarningRate").Trim();

  float.TryParse(warningRate,out Sys.WarningRate);

  string NetVersion = GetValue(doc, "Version").Trim();

  Version LocalVersion=System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

  return new Version(NetVersion).CompareTo(new Version(LocalVersion))>0;//大于0说明有新版本发布

  }//这个方法是载入网络配置文件,读取一些不想放在本地的配置参数,以及比较本地和网络版本号

  public static bool GoUpdate()

  {

  return DownLoadFile(Sys.UpdateFile,Sys.UpdateUrl);

  }

  public static string GetValue(XmlDocument doc, string Key)

  {

  string Value;

  try

  {

  XmlElement elem = (XmlElement)doc.SelectSingleNode(@"/config/app/" + Key);//读取配置文件可自行定义

  Value = elem == null ? "" : elem.GetAttribute("value");

  }

  catch

  {

  Value = "";

  }

  return Value;

  }

  public static XmlDocument loadXMLDocument(string FileNameOrUrl)

  {

  XmlDocument doc = null;

  try

  {

  doc = new XmlDocument();

  doc.Load( FileNameOrUrl);

  }

  catch (Exception e)

  {

  System.Windows.Forms.MessageBox.Show(e.Message);

  Pub.logError(e);

  doc = null;

  }

  return doc;

  }

  public static bool DownLoadFile(string FileName, string Url)

  {

  bool Value = false;

  WebResponse response = null;

  Stream stream = null;

  try

  {

  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);

  response = request.GetResponse();

  stream = response.GetResponseStream();

  if (!response.ContentType.ToLower().StartsWith("text/"))

  {

  Value = SaveBinaryFile(response, FileName);

  }

  }

  catch (Exception e)

  {

  // System.Windows.Forms.MessageBox.Show(e.Message);

  Pub.logError(e);

  }

  return Value;

  }

  private static bool SaveBinaryFile(WebResponse response, string FileName)

  {

  bool Value = true;

  byte[] buffer = new byte[1024];

  try

  {

  if (File.Exists(FileName))

  File.Delete(FileName);

  Stream outStream = System.IO.File.Create(FileName);

  Stream inStream = response.GetResponseStream();

  int l;

  do

  {

  l = inStream.Read(buffer, 0, buffer.Length);

  if (l > 0)

  outStream.Write(buffer, 0, l);

  }

  while (l > 0);

  outStream.Close();

  inStream.Close();

  }

  catch (Exception e)

  {

  System.Windows.Forms.MessageBox.Show(e.Message);

  Pub.logError(e);

  Value = false;

  }

  return Value;

  }

  }

  }

  2.本地配置文件可能如:

  <configuration>

  <appSettings>

  <add key="UpdateUrl" value="http://www.abc.com/download/release.xml" />

  </appSettings>

  </configuration>

  3.网络配置文件可能如:

  <config>

  <app>

  <Version value="1.1.9.2" />

  <ReleaseDate value="2006-12-12" />

  <DownloadPage value="http://www.abc.com/download/index.htm" />

  <DownloadURL value="http://www.abc.com/download/update.exe" />

  <WarningRate value="0.3" />

  </app>

  </config>

  4.调用示例

  在认为合适的时机(比如说应用程序启动时),启动一个后台线程去工作:

  Thread thread = new Thread(new ThreadStart(threadMethodUpdate));

  thread.Start();

  private void threadMethodUpdate()

  {

  if (VersionAgent.CheckNetwork())//网络状况正常

  {

  if (VersionAgent.CheckUpdate())//检查更新并获取网络参数

  {

  if (VersionAgent.GoUpdate())//获取新版本(由于我的软件很小,所以在不提示用户的情况就进行了新版下载,如认为不妥,可通过MessageBox提示一下)

  {

  MessageBox.Show("检测到产品的更新版本,即将开始自动更新!", "版本升级", MessageBoxButtons.OK, MessageBoxIcon.Information);

  System.Diagnostics.Process.Start(Sys.UpdateFile);

  System.Environment.Exit(0);

  }

  else

  {

  MessageBox.Show("系统检测到更新版本,但自动下载失败,点击确定进行手动下载", "版本升级", MessageBoxButtons.OK, MessageBoxIcon.Error);

  System.Diagnostics.Process.Start(Sys.UpdatePage);

  System.Environment.Exit(0);

  }

  }

  }

  else//也可以什么也不提示

  MessageBox.Show("无法连接到服务器进行自动升级!\n请检查网络连接 " + Pub.GetSetting("UpdateUrl"), "网络异常", MessageBoxButtons.OK, MessageBoxIcon.Warning);

  }