https://www.cnblogs.com/zhaopei/p/12840786.html
打包成单文件exe
通常我们开发出来的WinForm程序,除了一个exe文件还会有很多dll文件。
那么有没有办法只生成一个exe文件,让程序更加方便传播和使用,答案是肯定的。
NuGet搜索 Costura.Fody
并下载,然后重新生成解决方案即可,你在去bin目录查看,原来的一堆dll不见了。

.net core官方支持打包成单文件
如果你使用的.net core 3.0,那么你可以直接使用官方支持的发布单文件功能。
直接使用命令 dotnet publish -r win10-x64 /p:PublishSingleFile=true
或者修改一下项目文件
1 2 3 4 5 6 7 8 9 10 11 12 13
| <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <UseWindowsForms>true</UseWindowsForms> <RuntimeIdentifier>win10-x64</RuntimeIdentifier>//发布平台 <PublishSingleFile>true</PublishSingleFile>//是否单个exe </PropertyGroup> <PropertyGroup> <PublishTrimmed>true</PublishTrimmed>//启用压缩 </PropertyGroup> </Project>
|
自动升级更新
一个有生命的桌面程序理应做到可以自动升级。很多人在做自动升级更新时会执行一个单独的升级exe,也就是说一个完整的程序起码包括两个exe。个人觉得不够优雅,如果能用一个exe自己更新自己岂不是完美。思考如下:

自己更新自己 ,然后杀了自己,启动新的自己。
代码可参考 https://github.com/zhaopeiym/IoTClient/blob/master/IoTClient.Tool/IndexForm.cs
中的 CheckUpgradeAsync 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
private async Task CheckUpgradeAsync() { UpgradeFileManage(); HttpClient http = new HttpClient(); var content = new StringContent(JsonConvert.SerializeObject(new VersionCheckInput())); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await http.PostAsync("https://download.haojima.net/api/IoTClient/VersionCheck", content); var result = await response.Content.ReadAsStringAsync(); var VersionObj = JsonConvert.DeserializeObject<ResultBase<VersionCheckOutput>>(result); if (VersionObj.Code == 200 && VersionObj.Data.Code == 1) { if (MessageBox.Show("IoTClient有新版本,是否升级到最新版本?", "版本升级", MessageBoxButtons.OKCancel) == DialogResult.OK) { if (new UpgradeForm().ShowDialog() != DialogResult.OK) return; var newApp = Application.StartupPath + @"\temp." + Path.GetFileName(Application.ExecutablePath); Process.Start(newApp); Close(); Environment.Exit(0); } } }
private void UpgradeFileManage() { if (Path.GetFileName(Application.ExecutablePath).Contains("temp.")) { var filePath = Path.Combine(Application.StartupPath, Path.GetFileName(Application.ExecutablePath).Replace("temp.", "")); var newFilePath = filePath; try { try { if (File.Exists(filePath)) File.Delete(filePath); } catch (Exception) { Thread.Sleep(500); if (File.Exists(filePath)) File.Delete(filePath); } File.Copy(Application.ExecutablePath, newFilePath); Process.Start(filePath); Environment.Exit(0); } catch (Exception ex) { MessageBox.Show("升级失败 " + ex.Message); } } else { var filePath = Path.Combine(Application.StartupPath, "temp." + Path.GetFileName(Application.ExecutablePath)); try { if (File.Exists(filePath)) File.Delete(filePath); } catch (Exception) { Thread.Sleep(500); if (File.Exists(filePath)) File.Delete(filePath); } } }
|
下载新版本文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public UpgradeForm() { InitializeComponent(); TopMost = true; StartPosition = FormStartPosition.CenterScreen; FormBorderStyle = FormBorderStyle.FixedSingle; CheckForIllegalCrossThreadCalls = false; Task.Run(async () => { await DownloadAsync(); DialogResult = DialogResult.OK; Close(); }); }
public async Task DownloadAsync() { long downloadSize = 0; long downloadSpeed = 0; using (HttpClient http = new HttpClient()) { string contentType = "application/json"; http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType)); http.DefaultRequestHeaders.Add("Authorization", $"Bearer 043fc7d1a15bbaa6e48591baadc6f8ea");
var httpResponseMessage = await http.GetAsync("http://localhost/api/v1.0/niuNiuCalc/download?fileName=NiuNiuCalcCsClient.exe&clientType=PC", HttpCompletionOption.ResponseHeadersRead); var contentLength = httpResponseMessage.Content.Headers.ContentLength; if (contentLength == null) { MessageBox.Show("服务器忙,请稍后再试。"); return; } using (var stream = await httpResponseMessage.Content.ReadAsStreamAsync()) { var readLength = 102400; byte[] bytes = new byte[readLength]; int writeLength; var beginSecond = DateTime.Now.Second; var filePath = Application.StartupPath + @"\temp." + Path.GetFileName(Application.ExecutablePath); using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write)) { while ((writeLength = stream.Read(bytes, 0, readLength)) > 0) { fs.Write(bytes, 0, writeLength); downloadSize += writeLength; downloadSpeed += writeLength; progressBar1.Invoke((Action)(() => { var endSecond = DateTime.Now.Second; if (beginSecond != endSecond) { downloadSpeed = downloadSpeed / (endSecond - beginSecond); Text = "下载速度" + downloadSpeed / 1024 + "KB/S"; beginSecond = DateTime.Now.Second; downloadSpeed = 0; } progressBar1.Value = Math.Max((int)(downloadSize * 100 / contentLength), 1); })); } } } } }
|
部分更新可配置文件
Version.json 文件用于比较每个组件信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| { "Version": "1.0.01", "FileName": "DcMoitorTools.zip", "ReleaseTime": "2019-11-29 12:10:07", "UpdateContent": "修复一堆bug,添加一些功能,优化一些体验...", "Sha1": "703b9e5ae97e51c24b6ca774a6e97a5f0c608fa1", "Files": [ { "Name": "BD.Text.Test.dll", "Version": "1.0.0.10", "Path": "BD.Text.Test.dll", "Sha1": "852ac3cc7a75f4554c14f9901996ea409b692fa9" } ] }
|
效果图
