ClickOnce DIY全自动更新下载升级的自我实现
程序员文章站
2024-02-05 12:44:16
smartclient概念近来比较热,但在微软提出这个名词以前已经有大量的软件在这么做了,一方面是简化客户端的部署,一方面是提供自动升级的功能;对于传统的winform应用...
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);
}
微软在推出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);
}