第二步理论上我们该写客户端了,但是,在此之前,需要先介绍下一些必要的方法以及操作。
写代码还是要尽量的保证通用性,以便以后需要的时候可以拿来稍微改改甚至直接使用。所以在这里我们将自动更新的程序抽象出来,即对于客户端来说,它只包含三个文件(AutoUpdate.dll、AutoUpdate.exe、UpdateList.xml,如果是.NET Framework的话,其实是没有AutoUpdate.dll文件的,就一个exe就足够了。这也是我为什么一直不用NET Core来写Winform程序的原因之一);然后将这三个文件放到主程序的目录中即可。
然后就是传参调用,在Program文件中做了以下代码操作。所以调用的时候需要将主程序的执行目录以及进程名传过来,作用分别是再更新完后自动启动以及更新之前把相关的进程杀掉以便完成更新。.
同时可以看到在更新的时候,有一个图片旋转的动作,也一并放到此篇文章中。
开发环境:.NET Core 3.1
开发工具: Visual Studio 2019
实现代码:
//更新程序namespace AutoUpdate {static class Program {/// <summary>/// The main entry point for the application./// </summary>[STAThread]static void Main(string[] args) {if(args.Length != 1) {return;}var arg = args[0].Split("|*|");if(arg.Length == 0) {return;}string runPath = arg[0];string procesName = arg[1];Process[] processes = Process.GetProcesses();foreach(Process process in processes) {if(process.ProcessName == procesName) {process.Kill(true);}}Application.SetHighDpiMode(HighDpiMode.SystemAware);Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form_update(runPath));}}}
//主程序namespace AutoUpdate.Test {static class Program {/// <summary>/// The main entry point for the application./// </summary>[STAThread]static void Main() {Update();Application.SetHighDpiMode(HighDpiMode.SystemAware);Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}readonly static string updateXml = Application.StartupPath + "UpdateList.xml";/// <summary>/// 获取本地更新地址/// </summary>/// <returns></returns>static string GetUpdateUrl() {XElement xele = XElement.Load(updateXml);string url = xele.Element("url").Value;return url;}/// <summary>/// 获取本地更新文件/// </summary>/// <returns></returns>static string GetUpdateFiles() {XDocument xdoc = XDocument.Load(updateXml);var files = from f in xdoc.Root.Element("files").Elements() select new { name = f.Attribute("name").Value, version = f.Attribute("version").Value };return JsonConvert.SerializeObject(files);}/// <summary>/// 检查是否需要更新/// </summary>/// <returns></returns>static bool CheckUpdate() {string url = GetUpdateUrl();HttpResult httpResult = HttpUtil.HttpRequest(new HttpItem(url + "GetUpdateFiles", requestData: GetUpdateFiles()));if(httpResult.Status) {UpdateModel_Out output = JsonConvert.DeserializeObject<UpdateModel_Out>(httpResult.HttpStringData);if(output.updateList.Count > 0)return true;}return false;}static void Update() {if(CheckUpdate()) {string processName = Assembly.GetExecutingAssembly().GetName().Name;ProcessStartInfo info = new ProcessStartInfo(Application.StartupPath + "AutoUpdate.exe", Process.GetCurrentProcess().MainModule.FileName + "|*|" + processName);Process.Start(info);Environment.Exit(0);}}}}
public static class ImageEx {/// <summary>/// 旋转图片/// </summary>/// <param name="image"></param>/// <param name="angle"></param>/// <returns></returns>public static Image RotateImage(this Image image, float angle) {if(image == null)throw new ArgumentNullException("image");float dx = image.Width / 2.0f;float dy = image.Height / 2.0f;Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);Graphics g = Graphics.FromImage(rotatedBmp);g.TranslateTransform(dx, dy);g.RotateTransform(angle);g.TranslateTransform(-dx, -dy);g.DrawImage(image, new PointF(0, 0));g.Dispose();return rotatedBmp;}}
实现效果:

代码解析:这里可以关注下在主程序中的获取更新地址以及文件等方法,其实我这里是有重复判断的,即在主程序中判断了一遍,还会在更新程序中判断一遍,如果觉得不需要,可以执行选择去掉,全部交给更新程序去做。但是也就需要统一放在更新程序的入口中做处理了,相对而言,我觉得写两遍还是很方便。