Winform在线更新

引言

       2015年第一篇,Winform在线更新,算是重操旧业吧,09年刚到北京时一直做硬件联动编程,所以大多数时间都在搞Winform, 但是从来没做过在线更新这个功能,前几天参与部门另一个项目,上来就需要加一个在线更新。 该自动更新组件核心是圣殿骑士开发的,另外参考逆水寒龙使用情况,当我拿到这个组件源代码时并不知道如何去用,花了大半天时间也没调试通过,所以把我遇到的问题和解决方法记录下来,方便后续其他Coder使用时查看使用方法。

 

在线更新思路

1、请求远程站点Version.xml 或者请求Web服务器都可以,最主要是对比服务器端配置文件版本号和本地配置文件版本号。

2、从远程站点下载文件。

3、覆盖本地可执行文件及用到的Dll,当然覆盖之前需要关掉本地exe进程或者windows服务进程。

4、文件覆盖后修改本地配置文件AutoUpdater.config.

5、覆盖后重新启动可执行程序或者windows服务。

 

该AutoUpdater缺点(使用过程中已完善)

1、没看到圣殿骑士如何使用该组件,参考逆水寒龙Demo时,找到了主程序关闭的地方。

2、在下载文件时没有考虑到远程服务器新增文件时处理本地AutoUpdater.config,也就是说更新程序处理时是基于本地配置文件config.UpdateFileList。

3、没有针对windows服务处理进程(已完善windows服务处理类)。

 

使用时遇到的问题

1、不知道如何使用该组件?

     使用该组件时项目应该具备4部分:Web站点用于接受请求及下载需更新文件、AutoUpdater更新组件、MainApplication(也就是你的主程序)、UpdateApplication(更新程序入口,通过主程序启动,在这个程序内部调用AutoUpdater组件)。

Winform在线更新

 

2、 不知道合适去关闭主程序和windows服务

      后在看逆水寒龙的Demo中看到他是在文件下载前,当你点击确认下载时关闭进程。

   

if (bDownload)

            {

                //关闭windows service

                ServiceProcess serviceProcess = new ServiceProcess();

                serviceProcess.StopService();



                //关掉主程序

                OperProcess oper=new OperProcess();

                oper.InitUpdateEnvironment();





                DownloadConfirm dc = new DownloadConfirm(downloadList);

                if (this.OnShow != null)

                    this.OnShow();

                  

                if (DialogResult.OK == dc.ShowDialog())

                {

                    StartDownload(downloadList);

                }

}

 

3、文件下载后临时目录和源程序主目录口径不一致

     这个根据自己需要调整文件Copy、Move代码。我们的程序可执行文件和主要Dll都是放在一个单独的文件里而不是默认的Bin\Debug下。所以我的做法就是把下载文件从TempFolder移动到可执行源文件根目录下。具体代码在DownloadProgress窗体的ProcDownload方法中处理。

if (!string.IsNullOrEmpty(tempFolderPath))

                    {

                        oldPath = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);

                        newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME + tempUrlPath, file.FileName);

                    }

 

4、 文件下载移动复制后合适启动应用程序

      在更新程序里添加finally代码,启动windows服务、启动主程序、关闭更新程序(UpdateApplication)。

void InitAndCheck()

        {

            bool bHasError = false;

            IAutoUpdater autoUpdater = new AutoUpdater();



            try

            {

                autoUpdater.Update();

            }

            catch (WebException exp)

            {

                MessageBox.Show("Can not find the specified resource");

                bHasError = true;

            }

            catch (XmlException exp)

            {

                bHasError = true;

                MessageBox.Show("Download the upgrade file error");

            }

            catch (NotSupportedException exp)

            {

                bHasError = true;

                MessageBox.Show("Upgrade address configuration error");

            }

            catch (ArgumentException exp)

            {

                bHasError = true;

                MessageBox.Show("Download the upgrade file error");

            }

            catch (Exception exp)

            {

                bHasError = true;

                MessageBox.Show("An error occurred during the upgrade process");

            }

            finally

            {

                if (bHasError == true)

                {

                    try

                    {

                        autoUpdater.RollBack();

                    }

                    catch (Exception)

                    {

                        

                    }

                }

                ServiceProcess serviceProcess = new ServiceProcess();

                serviceProcess.StartService();



                OperProcess oper = new OperProcess();

                oper.StartProcess();

            }

        }

 

5、 当Web站点出现新增文件时没有同步到本地配置文件。

      看源代码是发现修改本地AutoUpdater.config是基于本地UpdateFileList,只需要把Web端新增文件信息添加到该List中,序列化本地config时就会同步。

LocalFile tempFile = null;

            foreach (RemoteFile file in listRemotFile.Values)

            {

                downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size));



                //把远程服务器新增文件加入config.UpdateFileList, 修改本地AutoUpdater.config时使用。

                tempFile = new LocalFile(file.Path, file.LastVer, file.Size);

                config.UpdateFileList.Add(tempFile);



                if (file.NeedRestart)

                    bNeedRestart = true;

            }

 

6、添加windows服务处理类

 

public class ServiceProcess

    {

        #region 判断window服务是否启动

        /// <summary>  

        /// 判断某个Windows服务是否启动  

        /// </summary>  

        /// <returns></returns>  

        private bool IsServiceStart(string serviceName)

        {

            ServiceController psc = new ServiceController(serviceName);

            bool bStartStatus = false;

            try

            {

                if (!psc.Status.Equals(ServiceControllerStatus.Stopped))

                {

                    bStartStatus = true;

                }



                return bStartStatus;

            }

            catch (Exception ex)

            {

                throw new Exception(ex.Message);

            }

        }

        #endregion



        #region 启动服务

        private bool StartService(string serviceName)

        {

            bool flag = true;

            if (ServiceIsExisted(serviceName))

            {

                System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);

                if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)

                {

                    service.Start();

                    for (int i = 0; i < 60; i++)

                    {

                        service.Refresh();

                        System.Threading.Thread.Sleep(1000);

                        if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)

                        {

                            break;

                        }

                        if (i == 59)

                        {

                            flag = false;

                        }

                    }

                }

            }

            return flag;

        }

        #endregion



        #region 停止服务

        private bool StopService(string serviceName)

        {

            bool flag = true;

            if (ServiceIsExisted(serviceName))

            {

                System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);

                if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)

                {

                    service.Stop();

                    for (int i = 0; i < 60; i++)

                    {

                        service.Refresh();

                        System.Threading.Thread.Sleep(1000);

                        if (service.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)

                        {

                            break;

                        }

                        if (i == 59)

                        {

                            flag = false;

                        }

                    }

                }

            }

            return flag;

        }

        #endregion



        #region 判断window服务是否存在

        private bool ServiceIsExisted(string serviceName)

        {

            ServiceController[] services = ServiceController.GetServices();

            foreach (ServiceController s in services)

            {

                if (s.ServiceName == serviceName)

                {

                    return true;

                }

            }

            return false;

        }

        #endregion



        #region 安装服务

        private void InstallService(IDictionary stateSaver, string filepath)

        {

            try

            {

                ServiceController service = new ServiceController("ServiceName");

                if (!ServiceIsExisted("ServiceName"))

                {

                    //Install Service  

                    AssemblyInstaller myAssemblyInstaller = new AssemblyInstaller();

                    myAssemblyInstaller.UseNewContext = true;

                    myAssemblyInstaller.Path = filepath;

                    myAssemblyInstaller.Install(stateSaver);

                    myAssemblyInstaller.Commit(stateSaver);

                    myAssemblyInstaller.Dispose();

                    //--Start Service  

                    service.Start();

                }

                else

                {

                    if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)

                    {

                        service.Start();

                    }

                }

            }

            catch (Exception ex)

            {

                

            }

        }

        #endregion



        #region 卸载windows服务

        private void UnInstallService(string filepath)

        {

            try

            {

                if (ServiceIsExisted("ServiceName"))

                {

                    //UnInstall Service  

                    AssemblyInstaller myAssemblyInstaller = new AssemblyInstaller();

                    myAssemblyInstaller.UseNewContext = true;

                    myAssemblyInstaller.Path = filepath;

                    myAssemblyInstaller.Uninstall(null);

                    myAssemblyInstaller.Dispose();

                }

            }

            catch (Exception ex)

            {

                

            }

        }

        #endregion



        public void StopService()

        {

            if (ServiceIsExisted("MyService"))

            {

                if (IsServiceStart("MyService"))

                {

                    this.StopService("MyService");

                }

            }

            

        }



        public void StartService()

        {



            if (ServiceIsExisted("MyService"))

            {

                if (!IsServiceStart("MyService"))

                {

                    this.StartService("MyService");   

                }

            }

          

        }

    }

 

 总结

      当有任何一个功能需要开发时先要弄懂其原理,并且能反复调试网上找来的源码,反复调试后能明白其中的原理才能更好的应用。初拿到这个功能时并不明白就想去集成,结果花了时间还没弄明白怎么使用。 再次感谢圣殿骑士和逆水寒龙的文章给我的启示。

      Demo下载 提取码99a9

 

你可能感兴趣的:(WinForm)