【问题标题】:Code to check for updates, install new version of app检查更新的代码,安装新版本的应用程序
【发布时间】:2016-05-19 17:46:42
【问题描述】:

我有一个使用 MSI 安装的 .NET 4 WPF 应用程序,它是通过 Visual Studio 安装项目生成的。一切都很好,除了我缺少单击一次部署功能,该功能检查加载时应用程序的新版本并下载/安装它们。我放弃了 Click Once Deployment,因为它似乎是一个半生不熟的解决方案,它让你做一些简单的事情,比如让你的应用在启动时运行。

我想知道是否有人可以向我展示任何类型的教程或代码,说明如何处理检查应用程序的新版本、下载应用程序的新版本以及在旧应用程序上安装新应用程序.这似乎是大多数 WPF 应用程序都希望拥有的东西,我很惊讶我在 google 上找不到任何相关信息。

【问题讨论】:

    标签: wpf .net-4.0


    【解决方案1】:

    得到它的工作,这是代码,这样其他人就不需要重新发明*了......

    public class VersionHelper
    {
        private string MSIFilePath = Path.Combine(Environment.CurrentDirectory, "HoustersCrawler.msi");
        private string CmdFilePath = Path.Combine(Environment.CurrentDirectory, "Install.cmd");
        private string MsiUrl = String.Empty;
    
        public bool CheckForNewVersion()
        {
            MsiUrl = GetNewVersionUrl();
            return MsiUrl.Length > 0;
        }
    
        public void DownloadNewVersion()
        {
            DownloadNewVersion(MsiUrl);
            CreateCmdFile();
            RunCmdFile();
            ExitApplication();
        }
    
        private string GetNewVersionUrl()
        {
            var currentVersion = Convert.ToInt32(ConfigurationManager.AppSettings["Version"]);
            //get xml from url.
            var url = ConfigurationManager.AppSettings["VersionUrl"].ToString();
            var builder = new StringBuilder();
            using (var stringWriter = new StringWriter(builder))
            {
                using (var xmlReader = new XmlTextReader(url))
                {
                    var doc = XDocument.Load(xmlReader);
                    //get versions.
                    var versions = from v in doc.Descendants("version")
                                   select new
                                   {
                                       Name = v.Element("name").Value,
                                       Number = Convert.ToInt32(v.Element("number").Value),
                                       URL = v.Element("url").Value,
                                       Date = Convert.ToDateTime(v.Element("date").Value)
                                   };
                    var version = versions.ToList()[0];
                    //check if latest version newer than current version.
                    if (version.Number > currentVersion)
                    {
                        return version.URL;
                    }
                }
            }
            return String.Empty;
        }
    
        private void DownloadNewVersion(string url)
        {
            //delete existing msi.
            if (File.Exists(MSIFilePath))
            {
                File.Delete(MSIFilePath);
            }
            //download new msi.
            using (var client = new WebClient())
            {
                client.DownloadFile(url, MSIFilePath);
            }
        }
    
        private void CreateCmdFile()
        {
            //check if file exists.
            if (File.Exists(CmdFilePath))
                File.Delete(CmdFilePath);
            //create new file.
            var fi = new FileInfo(CmdFilePath);
            var fileStream = fi.Create();
            fileStream.Close();
            //write commands to file.
            using (TextWriter writer = new StreamWriter(CmdFilePath))
            {
                writer.WriteLine(@"msiexec /i HoustersCrawler.msi /quiet");
            }
        }
    
        private void RunCmdFile()
        {//run command file to reinstall app.
            var p = new Process();
            p.StartInfo = new ProcessStartInfo("cmd.exe", "/c Install.cmd");
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            //p.WaitForExit();
        }
    
        private void ExitApplication()
        {//exit the app.
            Application.Current.Shutdown();
        }
    }
    

    【讨论】:

    • 非常好的答案。但最好使用msdn.microsoft.com/en-us/library/s3bf0xb2(v=vs.110).aspx检查版本
    • 编码不准确。您应该删除 2 个未使用的变量 - StringBuilder builder、StringWriter stringWriter。此外,在 funcs CreateCmdFile() 和 RunCmdFile() 中,您应该将硬编码的“HoustersCrawler.msi”和“Install.cmd”替换为已声明的变量 MSIFilePath 和 CmdFilePath。而且,应该引用这两个路径,如下所示: $"msiexec /i \"{MSIFilePath}\" /quiet"
    【解决方案2】:

    没有这样的内置或现成工具。在您的应用程序启动时,您可以运行执行以下操作的代码。

    1. 获取您的 http://myserver.com/myproduct/update.xml,您将在其中保存最新版本的设置和新更新 msi 文件的 url
    2. 如果有可用的更新与当前运行的版本不同,则使用 WebClient 下载文件并将其存储在临时文件夹中
    3. 然后您可以使用以下字符串创建一个批处理文件并将其存储在临时文件夹中
    msiexec /u {your product code}
    msiexec /i ..path to your new msi
    

    最后使用 Process.Start 执行您的批处理文件并退出您的应用程序。

    【讨论】:

    • 谢谢@Akash Kava 我现在很接近了,但请参阅下面的 msiexec 命令行卸载/安装问题。
    【解决方案3】:

    查看 Scott Hanselman 关于 manually update via clickonce 的博文。

    【讨论】:

    • 了解您没有使用 ClickOnce,但是,我的搜索将我带到了这里,这将帮助其他正在使用 CO:如何:以编程方式检查应用程序更新使用ClickOnce 部署 API msdn.microsoft.com/en-us/library/ms404263.aspx
    最近更新 更多