前言:
由于项目原因,要实施的客户离作者太远,考虑提供软件的在线升级功能.我们如何实现呢!先讲下思路.
思路:
先实现WEB端的开发,主要考虑使用WEBService技术,提供远程服务的调用函数,返回一个文件的字节内容,然后写一个升级程序客户端,分发给客户使用的机器中,(可以随客户的软件一起安装).该客户端程序主要连接webserivce,然后将文件保存到本地机(客户的机器)中.就可以实现!
实现的细节:
要考虑提供给客户软件版本问题,低版本的升级,最新版本的就不用升级.还要考虑用户名与密码在WEB端的认证!
使用技术:
ASP.Net WebService开发,客户端的异步调用WebService方法.数据库技术!
?
如果转载请说明出处,http://blog.csdn.Net/zerodj
作者主页:http://itbaby.jss.cn
注意:itbaby.jss.cn中,技术文章不再更新,全部转到blog.csdn.Net/zerodj中.
开始实现:
1.建立数据库,作者(itbaby)使用SQLSERVER2000
1)软件项目表:softlist(softid, softname, resume, loginname, loginpwd)
softid:编号
softname:软件名称
resume:介绍
loginname:客户登录名
loginpwd:密码
2)各个软件的版本表 SoftListVersion(softid, subid, version, UpdatePath, olefile)
softid:主表的软件编号
subid:各版本数据编号
version:软件版本
filename:升级文件名
olefile:升级文件的二进制内容,是image类型,(我主要存放MSI的安装包文件类型,可以使用C#做此类安装包文件)
3)建立一个视图,chkVersion,用于检查版本号
SELECT dbo.SoftListVersion.subid, dbo.softlist.softname, dbo.SoftListVersion.version
FROM dbo.softlist INNER JOIN
??????? dbo.SoftListVersion ON dbo.softlist.softid = dbo.SoftListVersion.softid
4)再建立一个视图,vOleFile,用于下载文件
SELECT dbo.SoftListVersion.subid, dbo.softlist.softname, dbo.SoftListVersion.filename,
??????? dbo.SoftListVersion.olefile, dbo.SoftListVersion.version
FROM dbo.softlist INNER JOIN
??????? dbo.SoftListVersion ON dbo.softlist.softid = dbo.SoftListVersion.softid
2.写一个WEBSERVICE
1)启动VS.Net2003,建立一个叫babyWebSvc的项目,项目类型为(ASP.Net WEB服务)
2)添加一个SoftUpdate.asmx的WEB服务
3)添加一个方法SearchVersion
view plaincopy to clipboardprint?
[WebMethod(Description="返回当前软件升级包的最高版本")]??
public string SearchVersion(string softname)??
{??
?? string sVersion = "";??
?? webmod.dbConnStart(); //(连接)作者自己的连接数据库类,用户自己完成数据库连接??
?? string strSQL = "select MAX(version) as MaxVerID from chkVersion where softname = @softname";??
?? SqlCommand sqlCmd = new SqlCommand(strSQL,webmod.sqlConn);??
?? sqlCmd.CommandTimeout = 0;??
?? sqlCmd.Parameters.Add("@softname",SqlDbType.VarChar).Value = softname;??
?? SqlDataReader sqlRd = sqlCmd.ExecuteReader();??
?? if(sqlRd.HasRows)??
?? {??
??? sqlRd.Read();??
??? sVersion = Convert.ToString(sqlRd["MaxVerID"]);??
?? }??
?? sqlRd.Close();??
?????
?? webmod.dbConnEnd(); //(断开连接)作者自己的连接数据库类,用户自己完成数据库连接??
?
?? return sVersion;??
}?
[WebMethod(Description="返回当前软件升级包的最高版本")]
public string SearchVersion(string softname)
{
?? string sVersion = "";
?? webmod.dbConnStart(); //(连接)作者自己的连接数据库类,用户自己完成数据库连接
?? string strSQL = "select MAX(version) as MaxVerID from chkVersion where softname = @softname";
?? SqlCommand sqlCmd = new SqlCommand(strSQL,webmod.sqlConn);
?? sqlCmd.CommandTimeout = 0;
?? sqlCmd.Parameters.Add("@softname",SqlDbType.VarChar).Value = softname;
?? SqlDataReader sqlRd = sqlCmd.ExecuteReader();
?? if(sqlRd.HasRows)
?? {
??? sqlRd.Read();
??? sVersion = Convert.ToString(sqlRd["MaxVerID"]);
?? }
?? sqlRd.Close();
??
?? webmod.dbConnEnd(); //(断开连接)作者自己的连接数据库类,用户自己完成数据库连接
?? return sVersion;
}
?
4)添加下载文件内容的方法DownloadSoft
view plaincopy to clipboardprint?
[WebMethod(Description="返回需要下载的文件字节")]??
public byte[] DownloadSoft(string UserName,string PassWord,string SoftDnldName,string SoftHeightVersion)??
{??
?? //(连接)作者自己的连接数据库类,用户自己完成数据库连接??
?? webmod.dbConnStart();??
?
?? //检查用户合法性??
?? bool bMember = CheckAuth(UserName,PassWord);//该WebService内的一个检查用户合法性的函数,用户可以自己完成??
?? if(!bMember)??
?? {??
??? webmod.dbConnEnd();??
??? return null;??
?? }??
?
?? byte[] b = null;??
?
?? //我们取出指定软件名称的最高版本的升级包??
?? string strSQL = "select olefile from vOleFile where (filename=@softname) and version=@ver";??
?? SqlCommand sqlCmd = new SqlCommand(strSQL,webmod.sqlConn);??
?? sqlCmd.CommandTimeout = 0;??
?? sqlCmd.Parameters.Add("@softname",SqlDbType.VarChar).Value = SoftDnldName;??
?? sqlCmd.Parameters.Add("@ver",???? SqlDbType.VarChar).Value = SoftHeightVersion;??
?? SqlDataReader sqlRd = sqlCmd.ExecuteReader();??
?? if(sqlRd.HasRows)??
?? {??
??? sqlRd.Read();??
??? b = (byte[])sqlRd["olefile"];//文件的字节内容??
?? }??
?? sqlRd.Close();??
?
?? //(断开连接)作者自己的连接数据库类,用户自己完成数据库连接??
?? webmod.dbConnEnd();??
?
?? return b;??
}?
[WebMethod(Description="返回需要下载的文件字节")]
public byte[] DownloadSoft(string UserName,string PassWord,string SoftDnldName,string SoftHeightVersion)
{
?? //(连接)作者自己的连接数据库类,用户自己完成数据库连接
?? webmod.dbConnStart();
?? //检查用户合法性
?? bool bMember = CheckAuth(UserName,PassWord);//该WebService内的一个检查用户合法性的函数,用户可以自己完成
?? if(!bMember)
?? {
??? webmod.dbConnEnd();
??? return null;
?? }
?? byte[] b = null;
?? //我们取出指定软件名称的最高版本的升级包
?? string strSQL = "select olefile from vOleFile where (filename=@softname) and version=@ver";
?? SqlCommand sqlCmd = new SqlCommand(strSQL,webmod.sqlConn);
?? sqlCmd.CommandTimeout = 0;
?? sqlCmd.Parameters.Add("@softname",SqlDbType.VarChar).Value = SoftDnldName;
?? sqlCmd.Parameters.Add("@ver",???? SqlDbType.VarChar).Value = SoftHeightVersion;
?? SqlDataReader sqlRd = sqlCmd.ExecuteReader();
?? if(sqlRd.HasRows)
?? {
??? sqlRd.Read();
??? b = (byte[])sqlRd["olefile"];//文件的字节内容
?? }
?? sqlRd.Close();
?? //(断开连接)作者自己的连接数据库类,用户自己完成数据库连接
?? webmod.dbConnEnd();
?? return b;
}
?
3.WEB服务的方法完成后,你自己可以启动,测试,我们现在来写客户端的升级程序,假定你在开发时的WEBSERVICE的URL为:http://localhost/babywebsvc/SoftUpdate.asmx,注意这个URL,我们是要在客户端引用的
4.启动VS.Net2003,建立一个C#的Windows项目,在默认的FORM上添加一个按钮,
5.添加一个新的文件类型(应用程序配置文件)App.config
App.Config文件的内容
view plaincopy to clipboardprint?
<?Xml version="1.0" encoding="utf-8"?>??
<configuration>??
?? <appSettings>??
??? <add key="user" value="test"/>??
??? <add key="pwd" value="test"/>??
??? <add key="babyRecordSoftName" value="TEST.EXE"/><!--记录在远程的数据库中的软件名称-->??
??? <add key="Version" value="1.0"/>??
?? </appSettings>??
</configuration>?
<?Xml version="1.0" encoding="utf-8"?>
<configuration>
?? <appSettings>
??? <add key="user" value="test"/>
??? <add key="pwd" value="test"/>
??? <add key="babyRecordSoftName" value="TEST.EXE"/><!--记录在远程的数据库中的软件名称-->
??? <add key="Version" value="1.0"/>
?? </appSettings>
</configuration>
?
6.我们在Form启动的LOAD事件中,添加如下代码
view plaincopy to clipboardprint?
private void Form1_Load(object sender, System.EventArgs e)??
{??
//读出版本号,该版本号是在AssemblyInfo.cs中由系统本身设置的,[assembly: AssemblyVersion("1.0")]??
//以后要更改,可以改此处的AssemblyInfo.cs中的版本号,例:[assembly: AssemblyVersion("1.1")]??
//我们的WEBSERVICE中需要这个数据做为参数??
?
string sVersion = Application.ProductVersion;??
?
?
//写到App.Cofing文件中,每次调用WEBSERVICE方法时,从App.Cofing中读取版本,你也可以直接使用Application.ProductVersion,我是为了统一管理,全部从config中读取??
this.SaveAppConfig("Version",sVersion);??
}??
?
?
//SaveAppConfig函数的内容??
public static void SaveAppConfig(string AppKey,string AppValue)??
{??
?? XmlDocument xDoc = new XmlDocument();??
?? xDoc.Load(Application.ExecutablePath + ".config");??
?
?? XmlNode xNode;??
?? XmlElement xElem1;??
?? XmlElement xElem2;??
?
?
?? xNode = xDoc.SelectSingleNode("//appSettings");??
?
?? xElem1 = (XmlElement)xNode.SelectSingleNode("//add[@key='" + AppKey + "']");??
?? if ( xElem1 != null ) xElem1.SetAttribute("value",AppValue);??
?? else?
?? {??
??? xElem2 = xDoc.CreateElement("add");??
??? xElem2.SetAttribute("key",AppKey);??
??? xElem2.SetAttribute("value",AppValue);??
??? xNode.AppendChild(xElem2);??
?? }??
?? xDoc.Save(Application.ExecutablePath + ".config");??
}?
private void Form1_Load(object sender, System.EventArgs e)
{
//读出版本号,该版本号是在AssemblyInfo.cs中由系统本身设置的,[assembly: AssemblyVersion("1.0")]
//以后要更改,可以改此处的AssemblyInfo.cs中的版本号,例:[assembly: AssemblyVersion("1.1")]
//我们的WEBSERVICE中需要这个数据做为参数
string sVersion = Application.ProductVersion;
//写到App.Cofing文件中,每次调用WEBSERVICE方法时,从App.Cofing中读取版本,你也可以直接使用Application.ProductVersion,我是为了统一管理,全部从config中读取
this.SaveAppConfig("Version",sVersion);
}
//SaveAppConfig函数的内容
public static void SaveAppConfig(string AppKey,string AppValue)
{
?? XmlDocument xDoc = new XmlDocument();
?? xDoc.Load(Application.ExecutablePath + ".config");
?? XmlNode xNode;
?? XmlElement xElem1;
?? XmlElement xElem2;
?? xNode = xDoc.SelectSingleNode("//appSettings");
?? xElem1 = (XmlElement)xNode.SelectSingleNode("//add[@key='" + AppKey + "']");
?? if ( xElem1 != null ) xElem1.SetAttribute("value",AppValue);
?? else
?? {
??? xElem2 = xDoc.CreateElement("add");
??? xElem2.SetAttribute("key",AppKey);
??? xElem2.SetAttribute("value",AppValue);
??? xNode.AppendChild(xElem2);
?? }
?? xDoc.Save(Application.ExecutablePath + ".config");
}
?
?
7.主要部分,开始调用webservice的方法!
准备工作:1)添加一个WEB引用,(先点菜单"项目"-"添加WEB引用"),在弹出中中输入url的路径:http://localhost/babywebsvc/SoftUpdate.asmx
?? 2)假定你在开发时的WEBSERVICE的URL:http://localhost/babywebsvc/SoftUpdate.asmx
?? 3)填入WEB引用名:AutoUpdateWebSvc
?? 4)点下按纽完成WEB引用的添加
?
8.在你的Button1_click事件中添加如下CODE,主要使用异步调用
view plaincopy to clipboardprint?
private string svcUser = "";??
private string svcPwd = "";??
private string svcSoftName = "";??
private string svcCurrVersion = "";??
private string svcDnldFileName = "Test.MSI";//下载下来的文件名,??
private byte[] fbyte = null; //下载后的升级文件的内容??
private void Button1_Click(object sender, System.EventArgs e)??
{??
//读取App.config文件中的配置信息??
svcUser = System.Configuration.ConfigurationSettings.AppSettings["user"]; //需要人证的用户名??
svcPwd = System.Configuration.ConfigurationSettings.AppSettings["pwd"];?? //认证密码??
svcSoftName = System.Configuration.ConfigurationSettings.AppSettings["babyRecordSoftName"];//软件名称??
svcCurrVersion = System.Configuration.ConfigurationSettings.AppSettings["Version"];//当前版本号??
?
?
?? try?
?? {??
??? AutoUpdateWebSvc.SoftUpdate aSvc = new AutoUpdateWebSvc.SoftUpdate();??
?
??? //此处可以改成自己实际应用时的URL,不管WEB引用是动态还是静态,调用都会指向该URL??
??? aSvc.Url = "http://localhost/babyWebSvc/SoftUpdate.asmx";??
?
??? if(Button1.Text.Trim() == "检 查")??
??? {??
???? //检查最新版本??
???? System.AsyncCallback cb = new AsyncCallback(SearchVersionCallBack);//异步回调方法,并检查是否有高版本的升级软件存在??
???? aSvc.BeginSearchVersion(svcSoftName,cb,aSvc);??
??? }??
??? else if(Button1.Text.Trim() == "升 级")??
??? {??
???? //开始调用下载服务??
???? InvokeDownload(); //函数体见下面的CODE??
??? }??
??????
?? }??
?? catch(Exception ex)??
?? {??
??? MessageBox.Show(ex.Message);??
?? }??
}??
?
?
//检查最新版本的异步回调方法??
private void SearchVersionCallBack(System.IAsyncResult ar)??
{??
?? if(ar==null)return;??
?? if(ar.IsCompleted)??
?? {??
??? try?
??? {??
???? AutoUpdateWebSvc.SoftUpdate aSvc = (AutoUpdateWebSvc.SoftUpdate)ar.AsyncState;??
???? string sVersion = aSvc.EndSearchVersion(ar);??
???? aSvc.Dispose();??
?
???????
???? if(svcCurrVersion.Trim() == sVersion.Trim())??
????? MessageBox.Show"你的软件当前版本已经是最新的了,无需进行升级...");??
???? else if((string.Compare(svcCurrVersion.Trim(),sVersion.Trim()))==-1)??
???? {??
????????
????? MessageBox.Show("你的软件当前版本比较低,可以进行升级...");??
????? Button1.Text = "升 级";??
???? }??
?
??? }??
??? catch(Exception ex)??
??? {??
???? MessageBox.Show(ex.Message);??
??? }??
?? }??
}??
?
?
//调用远程的WEB服务,开始下载??
private void InvokeDownload()??
{??
?? try?
?? {??
??? AutoUpdateWebSvc.SoftUpdate aSvc = new AutoUpdateWebSvc.SoftUpdate();??
??? //此处可以改成自己实际应用时的URL,不管WEB引用是动态还是静态,调用都会指向该URL??
??? aSvc.Url = "http://localhost/babyWebSvc/SoftUpdate.asmx";??
?
??? //开始下载??
??? System.AsyncCallback cb = new AsyncCallback(DownloadSoftCallBack);//异步回调方法,保存文件??
??? aSvc.BeginDownloadSoft(svcUser,svcPwd,svcDnldFileName,lblVersion.Text.Trim(),cb,aSvc);??
??????
?? }??
?? catch(Exception ex)??
?? {??
??? MessageBox.Show(ex.Message);??
?? }??
}??
?
//下载方法执行完成后,异步回调方法??
private void DownloadSoftCallBack(System.IAsyncResult ar)??
{??
?? if(ar==null)??
?? {??
??? MessageBox.Show("升级过程中出现错误,不能进行升级,请稍后再试...");??
??? return;??
?? }??
?? if(ar.IsCompleted)??
?? {??
??? try?
??? {??
???? AutoUpdateWebSvc.SoftUpdate aSvc = (AutoUpdateWebSvc.SoftUpdate)ar.AsyncState;??
???? fbyte = aSvc.EndDownloadSoft(ar);??
???? aSvc.Dispose();??
?
???? //使用线程,保存文件??
???? Thread th = new Thread(new ThreadStart(Save2Disk));??
???? th.Start();??
?
??? }??
??? catch(Exception ex)??
??? {??
???? MessageBox.Show("升级过程中出现错误,"+ex.Message);??
??? }??
?? }??
}??
?
?
//将下载下来的字节数组保存成文件??
private void Save2Disk()??
{??
?? try?
?? {??
??? FileInfo finfo = new FileInfo(Application.ExecutablePath+svcDnldFileName);??
??? if(finfo.Exists)finfo.Delete();//文件存在就删除它??
??? Stream stream = finfo.OpenWrite();??
?
??? prosBar.Maximum = fbyte.Length;//prosBar是一个进度条??
??? prosBar.Minimum = 0;??
??? prosBar.Step = 1;??
??? int i=0;??
??? foreach(byte b in fbyte)??
??? {??
???? stream.WriteByte(b);??
???? prosBar.Value += 1;??
??? }??
??? stream.Flush();??
??? stream.Close();??
?
??? DialogResult dr = MessageBox.Show("下载完成,是否现在就安装升级程序...","提示信息",MessageBoxButtons.OKCancel,MessageBoxIcon.Information,MessageBoxDefaultButton.Button1);??
??? if(dr == DialogResult.OK)??
??? {??
???? ExecSetup();//启动下载下来的安装程序,用户可以自己完成??
??? }??
?? }??
?? catch(Exception ex)??
?? {??
??? MessageBox.Show("升级过程中出现错误,"+ex.Message);??
?? }??
?? uiButton2.Enabled = true;??
}?
private string svcUser = "";
private string svcPwd = "";
private string svcSoftName = "";
private string svcCurrVersion = "";
private string svcDnldFileName = "Test.MSI";//下载下来的文件名,
private byte[] fbyte = null; //下载后的升级文件的内容
private void Button1_Click(object sender, System.EventArgs e)
{
//读取App.config文件中的配置信息
svcUser = System.Configuration.ConfigurationSettings.AppSettings["user"]; //需要人证的用户名
svcPwd = System.Configuration.ConfigurationSettings.AppSettings["pwd"];?? //认证密码
svcSoftName = System.Configuration.ConfigurationSettings.AppSettings["babyRecordSoftName"];//软件名称
svcCurrVersion = System.Configuration.ConfigurationSettings.AppSettings["Version"];//当前版本号
?? try
?? {
??? AutoUpdateWebSvc.SoftUpdate aSvc = new AutoUpdateWebSvc.SoftUpdate();
??? //此处可以改成自己实际应用时的URL,不管WEB引用是动态还是静态,调用都会指向该URL
??? aSvc.Url = "http://localhost/babyWebSvc/SoftUpdate.asmx";
??? if(Button1.Text.Trim() == "检 查")
??? {
???? //检查最新版本
???? System.AsyncCallback cb = new AsyncCallback(SearchVersionCallBack);//异步回调方法,并检查是否有高版本的升级软件存在
???? aSvc.BeginSearchVersion(svcSoftName,cb,aSvc);
??? }
??? else if(Button1.Text.Trim() == "升 级")
??? {
???? //开始调用下载服务
???? InvokeDownload(); //函数体见下面的CODE
??? }
???
?? }
?? catch(Exception ex)
?? {
??? MessageBox.Show(ex.Message);
?? }
}
//检查最新版本的异步回调方法
private void SearchVersionCallBack(System.IAsyncResult ar)
{
?? if(ar==null)return;
?? if(ar.IsCompleted)
?? {
??? try
??? {
???? AutoUpdateWebSvc.SoftUpdate aSvc = (AutoUpdateWebSvc.SoftUpdate)ar.AsyncState;
???? string sVersion = aSvc.EndSearchVersion(ar);
???? aSvc.Dispose();
????
???? if(svcCurrVersion.Trim() == sVersion.Trim())
????? MessageBox.Show"你的软件当前版本已经是最新的了,无需进行升级...");
???? else if((string.Compare(svcCurrVersion.Trim(),sVersion.Trim()))==-1)
???? {
?????
????? MessageBox.Show("你的软件当前版本比较低,可以进行升级...");
????? Button1.Text = "升 级";
???? }
??? }
??? catch(Exception ex)
??? {
???? MessageBox.Show(ex.Message);
??? }
?? }
}
//调用远程的WEB服务,开始下载
private void InvokeDownload()
{
?? try
?? {
??? AutoUpdateWebSvc.SoftUpdate aSvc = new AutoUpdateWebSvc.SoftUpdate();
??? //此处可以改成自己实际应用时的URL,不管WEB引用是动态还是静态,调用都会指向该URL
??? aSvc.Url = "http://localhost/babyWebSvc/SoftUpdate.asmx";
??? //开始下载
??? System.AsyncCallback cb = new AsyncCallback(DownloadSoftCallBack);//异步回调方法,保存文件
??? aSvc.BeginDownloadSoft(svcUser,svcPwd,svcDnldFileName,lblVersion.Text.Trim(),cb,aSvc);
???
?? }
?? catch(Exception ex)
?? {
??? MessageBox.Show(ex.Message);
?? }
}
//下载方法执行完成后,异步回调方法
private void DownloadSoftCallBack(System.IAsyncResult ar)
{
?? if(ar==null)
?? {
??? MessageBox.Show("升级过程中出现错误,不能进行升级,请稍后再试...");
??? return;
?? }
?? if(ar.IsCompleted)
?? {
??? try
??? {
???? AutoUpdateWebSvc.SoftUpdate aSvc = (AutoUpdateWebSvc.SoftUpdate)ar.AsyncState;
???? fbyte = aSvc.EndDownloadSoft(ar);
???? aSvc.Dispose();
???? //使用线程,保存文件
???? Thread th = new Thread(new ThreadStart(Save2Disk));
???? th.Start();
??? }
??? catch(Exception ex)
??? {
???? MessageBox.Show("升级过程中出现错误,"+ex.Message);
??? }
?? }
}
//将下载下来的字节数组保存成文件
private void Save2Disk()
{
?? try
?? {
??? FileInfo finfo = new FileInfo(Application.ExecutablePath+svcDnldFileName);
??? if(finfo.Exists)finfo.Delete();//文件存在就删除它
??? Stream stream = finfo.OpenWrite();
??? prosBar.Maximum = fbyte.Length;//prosBar是一个进度条
??? prosBar.Minimum = 0;
??? prosBar.Step = 1;
??? int i=0;
??? foreach(byte b in fbyte)
??? {
???? stream.WriteByte(b);
???? prosBar.Value += 1;
??? }
??? stream.Flush();
??? stream.Close();
??? DialogResult dr = MessageBox.Show("下载完成,是否现在就安装升级程序...","提示信息",MessageBoxButtons.OKCancel,MessageBoxIcon.Information,MessageBoxDefaultButton.Button1);
??? if(dr == DialogResult.OK)
??? {
???? ExecSetup();//启动下载下来的安装程序,用户可以自己完成
??? }
?? }
?? catch(Exception ex)
?? {
??? MessageBox.Show("升级过程中出现错误,"+ex.Message);
?? }
?? uiButton2.Enabled = true;
}
?
9:总结,客户端调用,是从,点击Buttton1开始,搜索版本号,SearchVersion,当找到高版本升级包时,开始执行下载的方法DownloadSoft,然后保存到本地Save2Disk.
不管客户端的调用是同步还是异步,WEBService的方法都是一样写的,只不过同步调用,是直接使用WEBService中的方法名称,异步调用则会由系统自动生成BeginXXX()与EndXXX()的方法名称,提供给你使用
?