├── .gitignore
├── LICENSE
├── README.md
└── src
├── AutoUpgrade.sln
├── ComponentInfo.cs
├── Demo.Client
├── Demo.Client.csproj
├── Program.cs
└── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Demo.Updater
├── Demo.Updater.csproj
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Program.cs
└── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Zl.AutoUpgrade.Core
├── AutoUpdater.cs
├── Exceptions.cs
├── IUpgradeService.cs
├── LogHelper.cs
├── Properties
│ └── AssemblyInfo.cs
├── UpgradeCmdArg.cs
├── UpgradeConfig.cs
├── UpgradeService.cs
├── UpgradeStatus.cs
├── Zl.AutoUpgrade.Core.csproj
├── Zl.AutoUpgrade.Core.nuspec
└── packages.config
├── Zl.AutoUpgrade.Shared
├── VersionService.cs
├── XmlSerializer.cs
├── Zl.AutoUpgrade.Shared.projitems
└── Zl.AutoUpgrade.Shared.shproj
└── Zl.AutoUpgrade.VersionInfoBuilder
├── FodyWeavers.xml
├── Program.cs
├── Properties
└── AssemblyInfo.cs
├── Zl.AutoUpgrade.VersionInfoBuilder.csproj
├── app.ico
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 ZengLong
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoUpgrade [](https://ci.appveyor.com/project/zenglong/autoupgrade/branch/master) [](https://www.nuget.org/packages/Zl.AutoUpgrade.Core)
2 | AutoUpgrade 是一个非常简单、轻量级的自动升级组件,以Ftp Server作为升级服务器,可自动升级托管的用户软件。
3 | AutoUpgrade 是用C#语言开发,基于 .Net Framework4.0 实现的,支持 Windows xp sp3 及以上版本的Windows系统。
4 |
5 | ## 组件组成
6 | AutoUpgrade 组件包含两个子组件。
7 |
8 | 子组件 | 对应的.Net项目 | 编译输出 | 说明
9 | ---------|----------|---------|---------
10 | 升级组件 | Zl.AutoUpgrade.Core | Zl.AutoUpgrade.Core.dll | 升级功能类库,供升级程序调用来完成升级任务。
11 | 版本信息生成工具 | Zl.AutoUpgrade.VersionInfoBuilder | VersionInfoBuilder.exe | 命令行工具,用于给升级补丁文件生成可被升级组件识别的补丁版本信息,只有包含该工具生成的版本信息文件的升级补丁包才可被升级组件下载升级。
12 |
13 | ## 开发说明
14 | 要集成AutoUpgrade需要基于`Zl.AutoUpgrade.Core`实现一个升级程序,用户软件需与升级程序相互配合功能完成用户软件升级。
15 | 一般我们需要在用户软件启动时自动检测补丁及尝试升级,我们可以在用户软件启动时先启动升级程序尝试升级,升级程序升级结束后再重新启动用户软件。
16 | ### 1. 创建升级程序项目
17 | 首先,需要创建一个exe项目作为升级程序项目,该项目通过调用升级组件实现升级控制逻辑,该项目需要引用`Zl.AutoUpgrade.Core`,而不应该依赖任何用户软件项目(用户软件自身功能的相关项目),以免升级时会因正在运行而无法覆盖更新。
18 | 源码中`Demo.Updater`项目为升级程序示例项目,其中包含了升级进度监听和提示功能。
19 | 如下为比较简单的参考实现:
20 | ``` CSharp
21 | [STAThread]
22 | public static void Main(string[] args)
23 | {
24 | //如果已有升级程序正在运行则退出,避免多个进程同时升级
25 | if (AutoUpdater.IsUpdaterRunning())
26 | {
27 | return;
28 | }
29 | //等待小会,避免用户软件尚未关闭而无法覆盖升级
30 | Thread.Sleep(1000);
31 | IUpgradeService upgradeService;
32 | //获取升级服务,该种方式的服务获取仅针对由用户软件内通过AutoUpdater.TryUpgrade启动的升级程序有效
33 | if (AutoUpdater.TryResolveUpgradeService(out upgradeService))
34 | {
35 | //尝试升级
36 | upgradeService.TryUpgradeNow();
37 | }
38 | //尝试升级结束,重新启动托管的用户软件
39 | AutoUpdater.RunManagedExe();
40 | }
41 | ```
42 | ### 2. 用户软件启动时自动升级
43 | 一般我们会在用户软件启动时进行一次自动升级,在用户软件的入口项目增加`Zl.AutoUpgrade.Core`引用,在入口的其实代码中调用尝试升级。
44 | 源码中`Demo.Client`项目为升级程序示例项目。
45 | 如下为参考实现:
46 | ``` CSharp
47 | [STAThread]
48 | public static void Main(string[] args)
49 | {
50 | try
51 | {
52 | var upgradeStatus = AutoUpdater.TryUpgrade(new UpgradeConfig()
53 | {
54 | FtpHost = "127.0.0.1", //ftp server 地址
55 | FtpUser = "zl",// ftp 用户名
56 | FtpPassword = "temp",// ftp 密码
57 | FtpOverTLS = true //是否基于TLS连接
58 | }, typeof(Demo.Updater.MainWindow).Assembly //升级程序exe位置或所在的程序集
59 | );
60 | switch (upgradeStatus)
61 | {
62 | case UpgradeStatus.Started:
63 | case UpgradeStatus.Upgrading:
64 | //升级程序已启动,待升级程序升级结束后会再次启动当前exe,这里直接先结束当前exe
65 | return;
66 | case UpgradeStatus.NoNewVersion:
67 | MessageBox.Show("没有新版不需要升级,可继续运行了!");
68 | break;
69 | case UpgradeStatus.Ended:
70 | MessageBox.Show("升级过程已结束,可继续运行了!");
71 | break;
72 | default:
73 | break;
74 | }
75 | }
76 | catch (Exception exc)
77 | {
78 | MessageBox.Show("启动升级程序时遇到错误,跳过本次升级,继续运行!");
79 | }
80 | //继续用户软件代码
81 | }
82 | ```
83 |
84 | ## 升级补丁发布说明
85 | 升级补丁是只指某一新版本相对上一版本需要更新的或需要增加的程序文件和资源文件的集合。将升级补丁的所有文件放入升级服务器(ftp server)中即可发布。
86 | ### 1. 自动升级服务器搭建
87 | 自动升级功能将ftp服务器作为自动升级服务器,需搭建一个或使用已有的ftp server用于存储托管软件的升级补丁,作为升级组件的升级补丁包源。
88 | 创建一个只读ftp账号,后续如果有升级补丁,将补丁文件及`VersionInfoBuilder.exe`生成的版本信息文件放置在该ftp账根目录中即完成了补丁发布。
89 |
90 | ### 2. 生成版本信息文件
91 | 升级补丁文件必须通过`VersionInfoBuilder.exe`工具生成对应的版本信息文件后才可被升级组件正常升级。
92 | `VersionInfoBuilder.exe`是一个命令行工具,最简单生成版本信息文件的方式是直接将VersionInfoBuilder.exe放入升级补丁文件所在文件夹,双击运行VersionInfoBuilder.exe即可自动生成。
93 | VersionInfoBuilder.exe包含的参数如下:
94 |
95 | 参数 | 说明
96 | ------- | -------
97 | [/TargetFolder\|/T] | 要生成版本文件的目标文件夹,生成版本文件后的文件夹才可作为升级包供升级
98 | [/SecretKey\|/S] | 版本信息秘钥,客户端只有与本生成器使用的秘钥一致时才可正常升级本生成器生成的版本升级包
99 | [/Ignore\|/I] | 目标文件夹中要忽略的文件,多个用空格间隔
100 | [/Help\|/H] | 查看帮助
101 |
102 | 也可在命令行中运行`VersionInfoBuilder.exe /H`查看参数帮助。
103 | **注意:不应该将`Zl.AutoUpgrade.Core.dll`和自建的升级程序项目作为升级补丁的一部分,否则会因这两个dll被升级过程运行时依赖而导致总是无法被覆盖升级,从而导致升级失败。**
104 |
--------------------------------------------------------------------------------
/src/AutoUpgrade.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2006
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zl.AutoUpgrade.Core", "Zl.AutoUpgrade.Core\Zl.AutoUpgrade.Core.csproj", "{A58CBF69-20A5-4C92-B47C-5C28C3E736F5}"
7 | EndProject
8 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Zl.AutoUpgrade.Shared", "Zl.AutoUpgrade.Shared\Zl.AutoUpgrade.Shared.shproj", "{1618087A-3CB4-45FA-84FF-1EA8B16BF7B6}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.Common", "1.Common", "{35C59932-3931-403D-AABA-80D81FD22FB0}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2.ForClient", "2.ForClient", "{77BA2A67-E3EC-4EAF-9C79-1874E4DF2F7A}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3.ForServer", "3.ForServer", "{DEAF28E9-C2E3-4FA3-ABFA-5846B64B3D63}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zl.AutoUpgrade.VersionInfoBuilder", "Zl.AutoUpgrade.VersionInfoBuilder\Zl.AutoUpgrade.VersionInfoBuilder.csproj", "{BF0BC324-A831-4316-A64A-F05BC2346C4A}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.Demo", "4.Demo", "{5BF4FD96-9033-41C8-B98B-561957F10789}"
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Updater", "Demo.Updater\Demo.Updater.csproj", "{9E4104B6-64D3-4606-9A27-EF66F4F66580}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Client", "Demo.Client\Demo.Client.csproj", "{D69BCB79-8AF8-4FF2-B036-04F1AFB65054}"
23 | EndProject
24 | Global
25 | GlobalSection(SharedMSBuildProjectFiles) = preSolution
26 | Zl.AutoUpgrade.Shared\Zl.AutoUpgrade.Shared.projitems*{1618087a-3cb4-45fa-84ff-1ea8b16bf7b6}*SharedItemsImports = 13
27 | Zl.AutoUpgrade.Shared\Zl.AutoUpgrade.Shared.projitems*{a58cbf69-20a5-4c92-b47c-5c28c3e736f5}*SharedItemsImports = 4
28 | Zl.AutoUpgrade.Shared\Zl.AutoUpgrade.Shared.projitems*{bf0bc324-a831-4316-a64a-f05bc2346c4a}*SharedItemsImports = 4
29 | EndGlobalSection
30 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
31 | Debug|Any CPU = Debug|Any CPU
32 | Release|Any CPU = Release|Any CPU
33 | EndGlobalSection
34 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
35 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5}.Release|Any CPU.Build.0 = Release|Any CPU
39 | {BF0BC324-A831-4316-A64A-F05BC2346C4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {BF0BC324-A831-4316-A64A-F05BC2346C4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {BF0BC324-A831-4316-A64A-F05BC2346C4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 | {BF0BC324-A831-4316-A64A-F05BC2346C4A}.Release|Any CPU.Build.0 = Release|Any CPU
43 | {9E4104B6-64D3-4606-9A27-EF66F4F66580}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {9E4104B6-64D3-4606-9A27-EF66F4F66580}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {9E4104B6-64D3-4606-9A27-EF66F4F66580}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {9E4104B6-64D3-4606-9A27-EF66F4F66580}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {D69BCB79-8AF8-4FF2-B036-04F1AFB65054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {D69BCB79-8AF8-4FF2-B036-04F1AFB65054}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {D69BCB79-8AF8-4FF2-B036-04F1AFB65054}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {D69BCB79-8AF8-4FF2-B036-04F1AFB65054}.Release|Any CPU.Build.0 = Release|Any CPU
51 | EndGlobalSection
52 | GlobalSection(SolutionProperties) = preSolution
53 | HideSolutionNode = FALSE
54 | EndGlobalSection
55 | GlobalSection(NestedProjects) = preSolution
56 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5} = {77BA2A67-E3EC-4EAF-9C79-1874E4DF2F7A}
57 | {1618087A-3CB4-45FA-84FF-1EA8B16BF7B6} = {35C59932-3931-403D-AABA-80D81FD22FB0}
58 | {BF0BC324-A831-4316-A64A-F05BC2346C4A} = {DEAF28E9-C2E3-4FA3-ABFA-5846B64B3D63}
59 | {9E4104B6-64D3-4606-9A27-EF66F4F66580} = {5BF4FD96-9033-41C8-B98B-561957F10789}
60 | {D69BCB79-8AF8-4FF2-B036-04F1AFB65054} = {5BF4FD96-9033-41C8-B98B-561957F10789}
61 | EndGlobalSection
62 | GlobalSection(ExtensibilityGlobals) = postSolution
63 | SolutionGuid = {0F8E21A1-252B-45D5-8FF7-55487E849BC8}
64 | EndGlobalSection
65 | EndGlobal
66 |
--------------------------------------------------------------------------------
/src/ComponentInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 |
4 | [assembly: AssemblyCompany("ZengLong")]
5 | [assembly: AssemblyProduct("AutoUpgrade")]
6 | [assembly: AssemblyCopyright("Copyright © 2017 ZengLong")]
7 | [assembly: AssemblyTrademark("Zl")]
8 | [assembly: AssemblyCulture("")]
9 |
10 | // 程序集的版本信息由下列四个值组成:
11 | //
12 | // 主版本
13 | // 次版本
14 | // 生成号
15 | // 修订号
16 | //
17 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
18 | // 方法是按如下所示使用“*”: :
19 | // [assembly: AssemblyVersion("1.0.*")]
20 | [assembly: AssemblyVersion("1.1.0.0")]
21 | [assembly: AssemblyFileVersion("1.1.0.0")]
22 |
--------------------------------------------------------------------------------
/src/Demo.Client/Demo.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D69BCB79-8AF8-4FF2-B036-04F1AFB65054}
8 | WinExe
9 | Demo.Client
10 | Demo.Client
11 | v4.0
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | Demo.Client.Program
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 4.0
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Code
57 |
58 |
59 | True
60 | True
61 | Resources.resx
62 |
63 |
64 | True
65 | Settings.settings
66 | True
67 |
68 |
69 | ResXFileCodeGenerator
70 | Resources.Designer.cs
71 |
72 |
73 | SettingsSingleFileGenerator
74 | Settings.Designer.cs
75 |
76 |
77 |
78 |
79 | {9e4104b6-64d3-4606-9a27-ef66f4f66580}
80 | Demo.Updater
81 |
82 |
83 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5}
84 | Zl.AutoUpgrade.Core
85 |
86 |
87 |
88 |
89 | $(ProjectDir)..\Zl.AutoUpgrade.VersionInfoBuilder\$(OutDir)VersionInfoBuilder.exe /t $(TargetDir) /i Demo.Updater
90 |
91 |
--------------------------------------------------------------------------------
/src/Demo.Client/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Windows;
10 | using Zl.AutoUpgrade.Core;
11 |
12 | namespace Demo.Client
13 | {
14 | class Program
15 | {
16 | [STAThread]
17 | public static void Main(string[] args)
18 | {
19 | try
20 | {
21 | var upgradeStatus = AutoUpdater.TryUpgrade(new UpgradeConfig()
22 | {
23 | FtpHost = "127.0.0.1", //ftp server 地址
24 | FtpUser = "zl",// ftp 用户名
25 | FtpPassword = "temp",// ftp 密码
26 | FtpOverTLS = true //是否基于TLS连接
27 | }, typeof(Demo.Updater.MainWindow).Assembly //升级程序exe位置或所在的程序集
28 | );
29 | switch (upgradeStatus)
30 | {
31 | case UpgradeStatus.Started:
32 | case UpgradeStatus.Upgrading:
33 | //升级程序已启动,待升级程序升级结束后会再次启动当前exe,这里直接先结束当前exe
34 | return;
35 | case UpgradeStatus.NoNewVersion:
36 | MessageBox.Show("没有新版不需要升级,可继续运行了!");
37 | break;
38 | case UpgradeStatus.Ended:
39 | MessageBox.Show("升级过程已结束,可继续运行了!");
40 | break;
41 | default:
42 | break;
43 | }
44 | }
45 | catch (Exception exc)
46 | {
47 | MessageBox.Show("启动升级程序时遇到错误,跳过本次升级,继续运行!");
48 | }
49 | //继续用户软件代码
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Demo.Client/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // 有关程序集的一般信息由以下
8 | // 控制。更改这些特性值可修改
9 | // 与程序集关联的信息。
10 | [assembly: AssemblyTitle("Demo.Client")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("Demo.Client")]
15 | [assembly: AssemblyCopyright("Copyright © 2017")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // 将 ComVisible 设置为 false 会使此程序集中的类型
20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
21 | //请将此类型的 ComVisible 特性设置为 true。
22 | [assembly: ComVisible(false)]
23 |
24 | //若要开始生成可本地化的应用程序,请设置
25 | //.csproj 文件中的 CultureYouAreCodingWith
26 | //例如,如果您在源文件中使用的是美国英语,
27 | //使用的是美国英语,请将 设置为 en-US。 然后取消
28 | //对以下 NeutralResourceLanguage 特性的注释。 更新
29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置
36 | //(未在页面中找到资源时使用,
37 | //或应用程序资源字典中找到时使用)
38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
39 | //(未在页面中找到资源时使用,
40 | //、应用程序或任何主题专用资源字典中找到时使用)
41 | )]
42 |
43 |
44 | // 程序集的版本信息由下列四个值组成:
45 | //
46 | // 主版本
47 | // 次版本
48 | // 生成号
49 | // 修订号
50 | //
51 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
52 | // 方法是按如下所示使用“*”: :
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/src/Demo.Client/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本: 4.0.30319.42000
5 | //
6 | // 对此文件的更改可能导致不正确的行为,如果
7 | // 重新生成代码,则所做更改将丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Demo.Client.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 强类型资源类,用于查找本地化字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 返回此类使用的缓存 ResourceManager 实例。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Demo.Client.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 覆盖当前线程的 CurrentUICulture 属性
56 | /// 使用此强类型的资源类的资源查找。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Demo.Client/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/Demo.Client/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Demo.Client.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Demo.Client/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Demo.Updater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9E4104B6-64D3-4606-9A27-EF66F4F66580}
8 | WinExe
9 | Demo.Updater
10 | Demo.Updater
11 | v4.0
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | Demo.Updater.Program
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 4.0
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | MSBuild:Compile
56 | Designer
57 |
58 |
59 | MainWindow.xaml
60 | Code
61 |
62 |
63 |
64 |
65 |
66 | Code
67 |
68 |
69 | True
70 | True
71 | Resources.resx
72 |
73 |
74 | True
75 | Settings.settings
76 | True
77 |
78 |
79 | ResXFileCodeGenerator
80 | Resources.Designer.cs
81 |
82 |
83 | SettingsSingleFileGenerator
84 | Settings.Designer.cs
85 |
86 |
87 |
88 |
89 | {a58cbf69-20a5-4c92-b47c-5c28c3e736f5}
90 | Zl.AutoUpgrade.Core
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/Demo.Updater/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Demo.Updater/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 | using Zl.AutoUpgrade.Core;
16 |
17 | namespace Demo.Updater
18 | {
19 | ///
20 | /// MainWindow.xaml 的交互逻辑
21 | ///
22 | public partial class MainWindow : Window
23 | {
24 | private Thread _updateThread;
25 | private IUpgradeService _upgradeService;
26 | public MainWindow()
27 | {
28 | InitializeComponent();
29 | this.Loaded += MainWindow_Loaded;
30 | }
31 |
32 | private void MainWindow_Loaded(object sender, RoutedEventArgs e)
33 | {
34 | if (!AutoUpdater.TryResolveUpgradeService(out _upgradeService))
35 | {
36 | this.Close();
37 | }
38 | _updateThread = new Thread(this.DoUpdate);
39 | _updateThread.Start();
40 | }
41 |
42 | private void DoUpdate()
43 | {
44 | if (_upgradeService.DetectNewVersion())
45 | {
46 | _upgradeService.UpgradeStarted += UpgradeService_UpgradeStarted;
47 | _upgradeService.UpgradeProgressChanged += UpgradeService_UpgradeProgressChanged;
48 | _upgradeService.UpgradeEnded += UpgradeService_UpgradeEnded;
49 | _upgradeService.TryUpgradeNow();
50 | _upgradeService.UpgradeStarted -= UpgradeService_UpgradeStarted;
51 | _upgradeService.UpgradeProgressChanged -= UpgradeService_UpgradeProgressChanged;
52 | _upgradeService.UpgradeEnded -= UpgradeService_UpgradeEnded;
53 | }
54 | }
55 | private void UpgradeService_UpgradeStarted(object sender, EventArgs e)
56 | {
57 | this.Dispatcher.BeginInvoke(new Action(() =>
58 | {
59 | this.txtlab.Text = "检测到新版本,正在升级...";
60 | }));
61 | }
62 |
63 | private void UpgradeService_UpgradeProgressChanged(object sender, UpgradeProgressArgs e)
64 | {
65 | this.Dispatcher.BeginInvoke(new Action(() =>
66 | {
67 | this.probar.Value = e.ProgressPercent;
68 | this.txtlab.Text = string.Format("正在升级({0:P0})...", e.ProgressPercent);
69 | }));
70 | }
71 |
72 | private void UpgradeService_UpgradeEnded(object sender, UpgradeEndedArgs e)
73 | {
74 | this.Dispatcher.BeginInvoke(new Action(() =>
75 | {
76 | if (e.EndedType == UpgradeEndedType.Completed)
77 | {
78 | this.txtlab.Text = "升级成功";
79 | this.DialogResult = true;
80 | }
81 | else if (e.ErrorException is ThreadAbortException)
82 | {
83 | this.txtlab.Text = "已取消升级";
84 | }
85 | else
86 | {
87 | this.txtlab.Text = "升级中遇到错误";
88 | MessageBox.Show(this, e.ErrorMessage, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
89 | this.DialogResult = true;
90 | }
91 | }));
92 | }
93 |
94 |
95 | private void Button_Click(object sender, RoutedEventArgs e)
96 | {
97 | this.DialogResult = false;
98 | }
99 |
100 | protected override void OnClosed(EventArgs e)
101 | {
102 | base.OnClosed(e);
103 | if (this.DialogResult != true)
104 | {
105 | //取消升级
106 | if (_updateThread != null)
107 | _updateThread.Abort();
108 | }
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Windows;
10 | using Zl.AutoUpgrade.Core;
11 |
12 | namespace Demo.Updater
13 | {
14 | class Program
15 | {
16 | [STAThread]
17 | public static void Main(string[] args)
18 | {
19 | if (AutoUpdater.IsUpdaterRunning())
20 | {
21 | return;
22 | }
23 | //等待小会,避免用户软件尚未关闭而无法覆盖升级
24 | Thread.Sleep(1000);
25 | new MainWindow().ShowDialog();
26 | AutoUpdater.RunManagedExe();
27 | }
28 |
29 | //[STAThread]
30 | //public static void Main(string[] args)
31 | //{
32 | // //如果已有升级程序正在运行则退出,避免多个进程同时升级
33 | // if (AutoUpdater.IsUpdaterRunning())
34 | // {
35 | // return;
36 | // }
37 | // //等待小会,避免用户软件尚未关闭而无法覆盖升级
38 | // Thread.Sleep(1000);
39 | // IUpgradeService upgradeService;
40 | // //获取升级服务,该种方式的服务获取仅针对由用户软件内通过AutoUpdater.TryUpgrade启动的升级程序有效
41 | // if (AutoUpdater.TryResolveUpgradeService(out upgradeService))
42 | // {
43 | // //尝试升级
44 | // upgradeService.TryUpgradeNow();
45 | // }
46 | // //尝试升级结束,重新启动托管的用户软件
47 | // AutoUpdater.RunManagedExe();
48 | //}
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // 有关程序集的一般信息由以下
8 | // 控制。更改这些特性值可修改
9 | // 与程序集关联的信息。
10 | [assembly: AssemblyTitle("Demo.Updater")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("Demo.Updater")]
15 | [assembly: AssemblyCopyright("Copyright © 2017")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // 将 ComVisible 设置为 false 会使此程序集中的类型
20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
21 | //请将此类型的 ComVisible 特性设置为 true。
22 | [assembly: ComVisible(false)]
23 |
24 | //若要开始生成可本地化的应用程序,请设置
25 | //.csproj 文件中的 CultureYouAreCodingWith
26 | //例如,如果您在源文件中使用的是美国英语,
27 | //使用的是美国英语,请将 设置为 en-US。 然后取消
28 | //对以下 NeutralResourceLanguage 特性的注释。 更新
29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置
36 | //(未在页面中找到资源时使用,
37 | //或应用程序资源字典中找到时使用)
38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
39 | //(未在页面中找到资源时使用,
40 | //、应用程序或任何主题专用资源字典中找到时使用)
41 | )]
42 |
43 |
44 | // 程序集的版本信息由下列四个值组成:
45 | //
46 | // 主版本
47 | // 次版本
48 | // 生成号
49 | // 修订号
50 | //
51 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
52 | // 方法是按如下所示使用“*”: :
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本: 4.0.30319.42000
5 | //
6 | // 对此文件的更改可能导致不正确的行为,如果
7 | // 重新生成代码,则所做更改将丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Demo.Updater.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 强类型资源类,用于查找本地化字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 返回此类使用的缓存 ResourceManager 实例。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Demo.Updater.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 覆盖当前线程的 CurrentUICulture 属性
56 | /// 使用此强类型的资源类的资源查找。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Demo.Updater.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Demo.Updater/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/AutoUpdater.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading;
8 | using Zl.AutoUpgrade.Shared;
9 |
10 | namespace Zl.AutoUpgrade.Core
11 | {
12 | public static class AutoUpdater
13 | {
14 | private static UpgradeCmdArg _upgradeCmdArg;
15 | private static Mutex _updaterMutex;
16 | private const string UpdatedSign = "UPDATEDSIGN";
17 |
18 | ///
19 | /// Updater是否正在运行
20 | ///
21 | ///
22 | public static bool IsUpdaterRunning()
23 | {
24 | bool notUpdating = false;
25 | _updaterMutex = new Mutex(true, "Zl.AutoUpgrade.Core.AutoUpdater", out notUpdating);
26 | return !notUpdating;
27 | }
28 |
29 | ///
30 | /// 由托管exe调用,尝试升级。如果返回true,托管exe应该退出程序,否则会因托管exe正在运行而无法正常升级,升级成功后Updater有义务调用RunManagedExe()再重新启动托管exe。
31 | ///
32 | /// 升级配置
33 | /// 自定义的Updater程序集
34 | /// 是否需要升级且已启动升级
35 | public static UpgradeStatus TryUpgrade(UpgradeConfig upgradeConfig, Assembly updaterExeAssembly)
36 | {
37 | return TryUpgrade(upgradeConfig, updaterExeAssembly.Location);
38 | }
39 |
40 | ///
41 | /// 由托管exe调用,尝试升级。如果返回true,托管exe应该退出程序,否则会因托管exe正在运行而无法正常升级,升级成功后Updater有义务调用RunManagedExe()再重新启动托管exe。
42 | ///
43 | /// 升级配置
44 | /// 自定义的Updater Exe文件路径
45 | /// 是否需要升级且已启动升级
46 | public static UpgradeStatus TryUpgrade(UpgradeConfig upgradeConfig, string updaterExeFileName)
47 | {
48 | FileInfo fileInfo = new FileInfo(updaterExeFileName);
49 | if (!fileInfo.Exists)
50 | {
51 | throw new Exception("Can't found the updater exe");
52 | }
53 | if (IsUpdaterRunning())
54 | {
55 | return UpgradeStatus.Upgrading;
56 | }
57 | var args = Environment.GetCommandLineArgs().ToList();
58 | args.RemoveAt(0);
59 | if (args.LastOrDefault() == UpdatedSign)
60 | {
61 | return UpgradeStatus.Ended;
62 | }
63 |
64 | IUpgradeService upgradeService = new UpgradeService(upgradeConfig);
65 |
66 | if (!upgradeService.DetectNewVersion())
67 | {
68 | return UpgradeStatus.NoNewVersion;
69 | }
70 | if (string.IsNullOrEmpty(upgradeConfig.TargetFolder))
71 | {
72 | upgradeConfig.TargetFolder = AppDomain.CurrentDomain.BaseDirectory;
73 | }
74 | else
75 | {
76 | upgradeConfig.TargetFolder = new DirectoryInfo(upgradeConfig.TargetFolder).FullName;
77 | }
78 | UpgradeCmdArg arg = new UpgradeCmdArg()
79 | {
80 | Config = upgradeConfig,
81 | ManagedExeFileName = System.Reflection.Assembly.GetEntryAssembly().Location,
82 | ManagedExeArguments = string.Join(" ", args)
83 | };
84 | System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
85 | startInfo.FileName = fileInfo.FullName;
86 | startInfo.Arguments = "\"" + Convert.ToBase64String(XmlSerializer.ToBinary(arg)) + "\"";
87 | System.Diagnostics.Process.Start(startInfo);
88 | return UpgradeStatus.Started;
89 | }
90 |
91 | ///
92 | /// 由Updater升级前调用,尝试创建升级服务对象,如果不能从启动程序中获取到启动配置参数则创建失败。
93 | ///
94 | ///
95 | /// 是否成功创建了升级服务
96 | public static bool TryResolveUpgradeService(out IUpgradeService upgradeService)
97 | {
98 | upgradeService = null;
99 | var runArgs = Environment.GetCommandLineArgs().ToList();
100 | runArgs.RemoveAt(0);
101 | if (runArgs.Count == 0)
102 | return false;
103 | try
104 | {
105 | byte[] argData = Convert.FromBase64String(runArgs[0]);
106 | _upgradeCmdArg = XmlSerializer.ToObject(argData);
107 | upgradeService = new UpgradeService(_upgradeCmdArg.Config);
108 | return true;
109 | }
110 | catch (Exception exc)
111 | {
112 | return false;
113 | }
114 | }
115 |
116 | ///
117 | /// 由Updater升级完毕后调用,运行托管exe
118 | ///
119 | public static void RunManagedExe()
120 | {
121 | _updaterMutex.ReleaseMutex();
122 | _updaterMutex.Dispose();
123 | System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
124 | startInfo.FileName = _upgradeCmdArg.ManagedExeFileName;
125 | startInfo.Arguments = _upgradeCmdArg.ManagedExeArguments + " " + UpdatedSign;
126 | System.Diagnostics.Process.Start(startInfo);
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Zl.AutoUpgrade.Core
7 | {
8 | public class RollbackException : UpgradeException
9 | {
10 | public RollbackException(string message, Exception inner) : base(message, inner)
11 | {
12 | }
13 | }
14 | public class DeleteTempFileException : UpgradeException
15 | {
16 | public DeleteTempFileException(string message, Exception inner) : base(message, inner)
17 | {
18 | }
19 | }
20 | public class ReplaceNewVersionException : UpgradeException
21 | {
22 | public ReplaceNewVersionException(string message, Exception inner) : base(message, inner)
23 | {
24 | }
25 | }
26 |
27 | ///
28 | /// 非法文件
29 | ///
30 | public class UnlawfulException : UpgradeException
31 | {
32 | public UnlawfulException(string message, Exception inner) : base(message, inner)
33 | {
34 | }
35 | }
36 | public class DownFileException : UpgradeException
37 | {
38 | public DownFileException(string message, Exception inner) : base(message, inner)
39 | {
40 | }
41 | }
42 | public class BackupFileException : UpgradeException
43 | {
44 | public BackupFileException(string message, Exception inner) : base(message, inner)
45 | {
46 | }
47 | }
48 | public class CreateVersionInfoException : UpgradeException
49 | {
50 | public CreateVersionInfoException(string message, Exception inner) : base(message, inner)
51 | {
52 | }
53 | }
54 | public class UpgradeException : Exception
55 | {
56 | public UpgradeException(string message, Exception inner) : base(message, inner)
57 | {
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/IUpgradeService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Zl.AutoUpgrade.Core
8 | {
9 | public interface IUpgradeService
10 | {
11 | ///
12 | /// 检测到新版本
13 | ///
14 | event EventHandler NewVersionDetected;
15 |
16 | event EventHandler UpgradeStarted;
17 |
18 | event EventHandler UpgradeProgressChanged;
19 |
20 | event EventHandler UpgradeEnded;
21 |
22 | ///
23 | /// 探测新版本时间间隔(毫秒)
24 | ///
25 | int DetectInterval { get; set; }
26 |
27 | ///
28 | /// 是否升级
29 | ///
30 | bool AutoUpgrade { get; set; }
31 |
32 | ///
33 | /// 开始自动检测
34 | ///
35 | void StartAutoDetect();
36 |
37 | ///
38 | /// 停止自动检测
39 | ///
40 | void StopAutoDetect();
41 |
42 | ///
43 | /// 探测是否有新版本
44 | ///
45 | ///
46 | bool DetectNewVersion();
47 | ///
48 | /// 尝试立即升级,如果有新版本
49 | ///
50 | bool TryUpgradeNow();
51 |
52 | }
53 |
54 | public class NewVersionDetectedArgs : EventArgs
55 | {
56 | ///
57 | /// 随后是否需要进行升级
58 | ///
59 | public bool ThenUpgrade { get; set; }
60 | }
61 |
62 | public class UpgradeProgressArgs : EventArgs
63 | {
64 | ///
65 | /// 进度百分比
66 | ///
67 | public float ProgressPercent { get; internal set; }
68 |
69 | }
70 | public class UpgradeEndedArgs : EventArgs
71 | {
72 | ///
73 | /// 进度百分比
74 | ///
75 | public UpgradeEndedType EndedType { get; }
76 |
77 | ///
78 | /// 错误异常, 如果是错误终止有值
79 | ///
80 | public Exception ErrorException { get; }
81 | ///
82 | /// 错误消息, 如果是错误终止有值
83 | ///
84 | public string ErrorMessage { get; }
85 |
86 | public UpgradeEndedArgs(string errorMessage, Exception errorException)
87 | {
88 | this.EndedType = UpgradeEndedType.ErrorAborted;
89 | this.ErrorMessage = errorMessage;
90 | this.ErrorException = errorException;
91 | }
92 |
93 | public UpgradeEndedArgs()
94 | {
95 | this.EndedType = UpgradeEndedType.Completed;
96 | }
97 | }
98 |
99 | public enum UpgradeEndedType
100 | {
101 | ///
102 | /// 顺利完成
103 | ///
104 | Completed,
105 | ///
106 | /// 错误终止
107 | ///
108 | ErrorAborted
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/LogHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Net;
6 | using System.IO;
7 |
8 | namespace Zl.AutoUpgrade.Core
9 | {
10 | class LogHelper
11 | {
12 | public static void Log(Exception e)
13 | {
14 | Log(e, null);
15 | }
16 |
17 | public static void Log(string info)
18 | {
19 | Log(info, (string)null);
20 | }
21 | public static void Log(string info, string rem, bool closeTime)
22 | {
23 | Log(info, null, rem, closeTime);
24 | }
25 | public static void Log(string info, Exception e)
26 | {
27 | Log(info, e, null);
28 | }
29 |
30 | public static void Log(Exception e, string rem)
31 | {
32 | Log(null, e, rem);
33 | }
34 |
35 | public static void Log(string info, string rem)
36 | {
37 | Log(info, null, rem);
38 | }
39 |
40 | public static void Log(string info, Exception e, string rem)
41 | {
42 | Log(info, e, rem, false);
43 | }
44 | public static void Log(string info, Exception e, string rem, bool closetime)
45 | {
46 | try
47 | {
48 | string logfile = AppDomain.CurrentDomain.BaseDirectory + "\\log\\" +
49 | (e == null ? "info_" : "exception_") +
50 | DateTime.Now.ToString("yyyy-MM-dd") +
51 | (rem == null ? "" : ("_" + rem)) + ".log";
52 | CreateLogDirectory();
53 | FileStream file = null;
54 | using (file = new FileStream(logfile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write))
55 | {
56 | StreamWriter sw = new StreamWriter(file, Encoding.UTF8);
57 | if (!closetime)
58 | sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
59 | if (info != null)
60 | sw.WriteLine(info);
61 | if (e != null)
62 | sw.WriteLine(e.ToString());
63 | sw.Flush();
64 | sw.Close();
65 | }
66 | }
67 | catch (Exception)
68 | {
69 | }
70 | }
71 |
72 | public static void CreateLogDirectory()
73 | {
74 | Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + "\\log");
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Zl.AutoUpgrade.Core")]
9 | [assembly: AssemblyDescription("一个非常简单、轻量级的自动升级组件,以Ftp Server作为升级服务器,可自动升级其托管的Windows软件")]
10 | [assembly: AssemblyConfiguration("")]
11 |
12 | // 将 ComVisible 设置为 false 会使此程序集中的类型
13 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
14 | //请将此类型的 ComVisible 特性设置为 true。
15 | [assembly: ComVisible(false)]
16 |
17 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
18 | [assembly: Guid("a58cbf69-20a5-4c92-b47c-5c28c3e736f5")]
19 |
20 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/UpgradeCmdArg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Zl.AutoUpgrade.Core
7 | {
8 | public class UpgradeCmdArg
9 | {
10 | public UpgradeConfig Config { get; set; }
11 |
12 | public string ManagedExeFileName { get; set; }
13 |
14 | public string ManagedExeArguments { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/UpgradeConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Authentication;
5 | using System.Text;
6 |
7 | namespace Zl.AutoUpgrade.Core
8 | {
9 | public class UpgradeConfig
10 | {
11 | ///
12 | /// 要升级的目标目录,缺省程序所在目录
13 | ///
14 | public string TargetFolder { get; set; }
15 | ///
16 | /// 升级服务器ftp主机域名或ip
17 | ///
18 | public string FtpHost { get; set; }
19 | ///
20 | /// 升级服务器ftp用户名
21 | ///
22 | public string FtpUser { get; set; }
23 | ///
24 | /// 升级服务器ftp密码
25 | ///
26 | public string FtpPassword { get; set; }
27 | ///
28 | /// 是否使用TLS协议连接ftp
29 | ///
30 | public bool FtpOverTLS { get; set; }
31 | ///
32 | /// 当检测到新版后是否自动升级
33 | ///
34 | public bool AutoUpgrade { get; set; }
35 |
36 | ///
37 | /// 版本信息秘钥,只有与生成升级版本信息的生成器使用的秘钥一致时才可生成,缺省为"Zl.AutoUpgrade.SecretKey"
38 | ///
39 | public string VersionInfoSecretKey { get; set; }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/UpgradeService.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Zl.AutoUpgrade.Shared;
10 | using System.Security.Authentication;
11 |
12 | namespace Zl.AutoUpgrade.Core
13 | {
14 | public class UpgradeService : IUpgradeService
15 | {
16 | private string _targetFolder;
17 | private string _ftpServerIp;
18 | private string _ftpUser;
19 | private string _ftpPassword;
20 | private bool _ftpOverTLS;
21 | private VersionService _versionService;
22 | private const string VersionFileName = "versionInfo.xml";
23 | private static readonly string NewVersionTempFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "newVersionTemp");
24 | private static readonly string LastVersionBakFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lastVersionBak");
25 |
26 | public int DetectInterval { get; set; } = 1 * 60 * 1000;
27 | public bool AutoUpgrade { get; set; } = true;
28 |
29 | public event EventHandler NewVersionDetected;
30 | public event EventHandler UpgradeStarted;
31 | public event EventHandler UpgradeProgressChanged;
32 | public event EventHandler UpgradeEnded;
33 |
34 |
35 | public UpgradeService(UpgradeConfig config)
36 | {
37 | if (string.IsNullOrEmpty(config.TargetFolder))
38 | {
39 | this._targetFolder = AppDomain.CurrentDomain.BaseDirectory;
40 | }
41 | else
42 | {
43 | this._targetFolder = config.TargetFolder;
44 | }
45 | this._ftpServerIp = config.FtpHost;
46 | this._ftpUser = config.FtpUser;
47 | this._ftpPassword = config.FtpPassword;
48 | this._ftpOverTLS = config.FtpOverTLS;
49 | _versionService = new VersionService(config.VersionInfoSecretKey ?? "Zl.AutoUpgrade.SecretKey");
50 | }
51 |
52 | public void StartAutoDetect()
53 | {
54 | throw new NotImplementedException();
55 | }
56 |
57 | public void StopAutoDetect()
58 | {
59 | throw new NotImplementedException();
60 | }
61 |
62 | public bool DetectNewVersion()
63 | {
64 | using (FtpClient client = this.CreateFtpClient())
65 | {
66 | PackageVersionInfo diffVersionInfo = GetDifferenceVersionInfoWithServer(client);
67 | return diffVersionInfo != null && diffVersionInfo.Files.Length > 0;
68 | }
69 | }
70 |
71 | public bool TryUpgradeNow()
72 | {
73 | using (FtpClient client = this.CreateFtpClient())
74 | {
75 | PackageVersionInfo diffVersionInfo = GetDifferenceVersionInfoWithServer(client);
76 | if (diffVersionInfo == null || diffVersionInfo.Files.Length == 0)
77 | {
78 | return false;
79 | }
80 | UpgradeNow(client, diffVersionInfo);
81 | return true;
82 | }
83 | }
84 |
85 | private void UpgradeNow(FtpClient client, PackageVersionInfo diffVersionInfo)
86 | {
87 | this.RaiseUpgradeStarted();
88 | float percent = 0f;
89 | try
90 | {
91 | Directory.CreateDirectory(_targetFolder);
92 | var currVersionInfo = this._versionService.ComputeVersionInfo(_targetFolder);
93 | XmlSerializer.SaveToFile(diffVersionInfo, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "versionInfo_diff.xml"));
94 | XmlSerializer.SaveToFile(currVersionInfo, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "versionInfo_curr.xml"));
95 | this.RaiseUpgradeProgress(percent += 0.01f);
96 | }
97 | catch (Exception exc)
98 | {
99 | string msg = "计算版本信息文件出错";
100 | Exception nexc = new CreateVersionInfoException(msg, exc);
101 | this.RaiseUpgradeEnded(msg, nexc);
102 | throw nexc;
103 | }
104 | //下载新版本,占比 90%
105 | string curentDownFile = string.Empty;
106 | try
107 | {
108 | DirectoryInfo newVersionTemp = Directory.CreateDirectory(NewVersionTempFolder);
109 | client.RetryAttempts = 3;
110 | long downLength = 0;
111 | foreach (var item in diffVersionInfo.Files)
112 | {
113 | curentDownFile = item.File;
114 | client.DownloadFile(Path.Combine(newVersionTemp.FullName, item.File.TrimStart('\\', '/')), item.File.Replace('\\', '/'), true, FtpVerify.Retry);
115 | downLength += item.Length;
116 | this.RaiseUpgradeProgress(percent += (float)Math.Round((downLength * 1.0 / diffVersionInfo.TotalLength * 0.9), 2));
117 | }
118 | XmlSerializer.SaveToFile(diffVersionInfo, Path.Combine(newVersionTemp.FullName, VersionFileName));
119 | }
120 | catch (Exception exc)
121 | {
122 | string msg = string.Format("下载新版文件({0})出错", curentDownFile);
123 | Exception nexc = new DownFileException(msg, exc);
124 | this.RaiseUpgradeEnded(msg, nexc);
125 | throw nexc;
126 | }
127 | //验证文件合法性,防篡改,占比 1%
128 | try
129 | {
130 | if (!this._versionService.Verify(diffVersionInfo, NewVersionTempFolder))
131 | {
132 | string msg = "新版文件不合法";
133 | Exception nexc = new UnlawfulException(msg, null);
134 | this.RaiseUpgradeEnded(msg, nexc);
135 | throw nexc;
136 | }
137 | this.RaiseUpgradeProgress(percent += 0.01f);
138 | }
139 | catch (UnlawfulException)
140 | {
141 | throw;
142 | }
143 | catch (Exception exc)
144 | {
145 | string msg = "新版文件验证出错";
146 | Exception nexc = new UnlawfulException(msg, exc);
147 | this.RaiseUpgradeEnded(msg, nexc);
148 | throw nexc;
149 | }
150 | //备份当前版本,占比 3%
151 | try
152 | {
153 | CopyVersionFile(diffVersionInfo, this._targetFolder, LastVersionBakFolder);
154 | this.RaiseUpgradeProgress(percent += 0.03f);
155 | }
156 | catch (Exception exc)
157 | {
158 | string msg = "版本当前版本出错";
159 | Exception nexc = new BackupFileException(msg, exc);
160 | this.RaiseUpgradeEnded(msg, nexc);
161 | throw nexc;
162 | }
163 | //新版覆盖当前版,占比 4%
164 | try
165 | {
166 | CopyVersionFile(diffVersionInfo, NewVersionTempFolder, this._targetFolder);
167 | XmlSerializer.SaveToFile(diffVersionInfo, Path.Combine(this._targetFolder, VersionFileName));
168 | this.RaiseUpgradeProgress(percent += 0.04f);
169 | }
170 | catch (Exception exc)
171 | {
172 | try
173 | {
174 | CopyVersionFile(diffVersionInfo, LastVersionBakFolder, this._targetFolder);
175 | }
176 | catch (Exception exc1)
177 | {
178 | string msg1 = string.Format("新版覆盖当前版出错后回滚出错", curentDownFile);
179 | Exception nexc1 = new RollbackException(msg1, exc1);
180 | LogHelper.Log(nexc1, "升级忽略错误");
181 | }
182 | string msg = string.Format("新版覆盖当前版出错", curentDownFile);
183 | Exception nexc = new ReplaceNewVersionException(msg, exc);
184 | this.RaiseUpgradeEnded(msg, nexc);
185 | throw nexc;
186 | }
187 | //删除临时文件,占比 1%
188 | try
189 | {
190 | Directory.Delete(NewVersionTempFolder, true);
191 | Directory.Delete(LastVersionBakFolder, true);
192 | this.RaiseUpgradeProgress(percent += 0.01f);
193 | }
194 | catch (Exception exc)
195 | {
196 | string msg = string.Format("删除临时文件出错", curentDownFile);
197 | Exception nexc = new DeleteTempFileException(msg, exc);
198 | LogHelper.Log(nexc, "升级忽略错误");
199 | }
200 | this.RaiseUpgradeProgress(percent = 1f);
201 | this.RaiseUpgradeEnded();
202 | }
203 |
204 | private static void CopyVersionFile(PackageVersionInfo versionInfo, string sourceFolder, string toFolder)
205 | {
206 | foreach (var item in versionInfo.Files)
207 | {
208 | string filePath = Path.Combine(sourceFolder, item.File.TrimStart('\\', '/'));
209 | if (!File.Exists(filePath))
210 | {
211 | continue;
212 | }
213 | string newFilePath = Path.Combine(toFolder, item.File.TrimStart('\\', '/'));
214 | Directory.CreateDirectory(Directory.GetParent(newFilePath).FullName);
215 | File.Copy(filePath, newFilePath, true);
216 | }
217 | }
218 |
219 | private FtpClient CreateFtpClient()
220 | {
221 | FtpClient client = new FtpClient(_ftpServerIp, _ftpUser, _ftpPassword);
222 | client.DataConnectionType = FtpDataConnectionType.AutoActive;
223 | if (_ftpOverTLS)
224 | {
225 | client.EncryptionMode = FtpEncryptionMode.Explicit;
226 | client.SslProtocols = SslProtocols.Tls;
227 | client.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
228 | }
229 | return client;
230 | }
231 | private void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e)
232 | {
233 | // add logic to test if certificate is valid here
234 | e.Accept = true;
235 | }
236 |
237 | private PackageVersionInfo GetDifferenceVersionInfoWithServer(FtpClient client)
238 | {
239 | if (!client.FileExists("/" + VersionFileName))
240 | {
241 | return null;
242 | }
243 | byte[] versionData = null;
244 | if (!client.Download(out versionData, "/" + VersionFileName))
245 | {
246 | return null;
247 | }
248 | PackageVersionInfo pvi = XmlSerializer.ToObject(versionData);
249 | return this._versionService.CompareDifference(_targetFolder, pvi);
250 | }
251 |
252 | ///
253 | /// 复制文件夹(及文件夹下所有子文件夹和文件)
254 | ///
255 | /// 待复制的文件夹路径
256 | /// 目标路径
257 | private static void CopyDirectory(String sourcePath, String destinationPath, params DirectoryInfo[] withoutFolders)
258 | {
259 | DirectoryInfo info = new DirectoryInfo(sourcePath);
260 | Directory.CreateDirectory(destinationPath);
261 | foreach (FileSystemInfo fsi in info.GetFileSystemInfos())
262 | {
263 | String destName = Path.Combine(destinationPath, fsi.Name);
264 |
265 | if (fsi is System.IO.FileInfo)
266 | File.Copy(fsi.FullName, destName, true);
267 | else
268 | {
269 | if (withoutFolders != null && withoutFolders.Any(m => m.FullName.ToUpper().TrimEnd('/', '\\')
270 | == fsi.FullName.ToUpper().TrimEnd('/', '\\')))
271 | {
272 | break;
273 | }
274 | Directory.CreateDirectory(destName);
275 | CopyDirectory(fsi.FullName, destName);
276 | }
277 | }
278 | }
279 |
280 | private void RaiseUpgradeStarted()
281 | {
282 | EventHandler handler = this.UpgradeStarted;
283 | if (handler != null)
284 | {
285 | handler.BeginInvoke(this, EventArgs.Empty, null, null);
286 | }
287 | }
288 | private void RaiseUpgradeEnded()
289 | {
290 | EventHandler handler = this.UpgradeEnded;
291 | if (handler != null)
292 | {
293 | handler.BeginInvoke(this, new UpgradeEndedArgs(), null, null);
294 | }
295 | }
296 | private void RaiseUpgradeEnded(string errorMessage, Exception errorException)
297 | {
298 | EventHandler handler = this.UpgradeEnded;
299 | if (handler != null)
300 | {
301 | handler.BeginInvoke(this, new UpgradeEndedArgs(errorMessage, errorException), null, null);
302 | }
303 | }
304 | private void RaiseUpgradeProgress(float percent)
305 | {
306 | EventHandler handler = this.UpgradeProgressChanged;
307 | if (handler != null)
308 | {
309 | handler.BeginInvoke(this, new UpgradeProgressArgs() { ProgressPercent = percent }, null, null);
310 | }
311 | }
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/UpgradeStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Zl.AutoUpgrade.Core
7 | {
8 | public enum UpgradeStatus
9 | {
10 | ///
11 | /// 未检测到新版本
12 | ///
13 | NoNewVersion,
14 | ///
15 | /// 升级开始
16 | ///
17 | Started,
18 | ///
19 | /// 升级结束
20 | ///
21 | Ended,
22 | ///
23 | /// 正在升级
24 | ///
25 | Upgrading
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/Zl.AutoUpgrade.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {A58CBF69-20A5-4C92-B47C-5C28C3E736F5}
8 | Library
9 | Properties
10 | Zl.AutoUpgrade.Core
11 | Zl.AutoUpgrade.Core
12 | v4.0
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\FluentFTP.19.1.0\lib\net40\FluentFTP.dll
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Properties\ComponentInfo.cs
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/Zl.AutoUpgrade.Core.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | $author$
8 | $author$
9 | https://github.com/zenglo/AutoUpgrade/blob/master/LICENSE
10 | https://github.com/zenglo/AutoUpgrade
11 | false
12 | $description$
13 | First release.
14 | Copyright 2017
15 | AutoUpgrade AutoUpdate ftpupdate
16 |
17 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Core/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Shared/VersionService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Security.Cryptography;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Xml.Serialization;
8 |
9 | namespace Zl.AutoUpgrade.Shared
10 | {
11 |
12 | class VersionService
13 | {
14 | private string SecretKey = "Zl.AutoUpgrade.SecretKey";
15 |
16 | ///
17 | /// 构造版本服务
18 | ///
19 | /// 版本信息秘钥,用语加密版本信息
20 | public VersionService(string secretKey)
21 | {
22 | SecretKey = secretKey;
23 | }
24 |
25 | ///
26 | /// 对比版本包中的文件emd5值是否完全与指定文件夹中对应文件相同,鉴别是否中途遭恶意更改
27 | ///
28 | ///
29 | ///
30 | ///
31 | public bool Verify(PackageVersionInfo romotePackageVersionInfo, string localFolderPath)
32 | {
33 | CspParameters param = new CspParameters();
34 | param.KeyContainerName = SecretKey;
35 | DirectoryInfo directoryInfo = new DirectoryInfo(localFolderPath + "/");
36 | using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
37 | {
38 | using (MD5 md5 = new MD5CryptoServiceProvider())
39 | {
40 | foreach (var item in romotePackageVersionInfo.Files)
41 | {
42 | string filePath = System.IO.Path.Combine(directoryInfo.FullName, item.File.TrimStart('\\', '/'));
43 | FileInfo fileInfo = new FileInfo(filePath);
44 | if (!File.Exists(filePath))
45 | {
46 | return false;
47 | }
48 | string emd5Str = ComputeEmd5(fileInfo, md5, rsa);
49 | if (emd5Str != item.Emd5)
50 | {
51 | return false;
52 | }
53 | }
54 | }
55 | }
56 | return true;
57 | }
58 | ///
59 | /// 对比本地文件与远程文件的版本信息,得出需要升级的所有文件版本信息
60 | ///
61 | ///
62 | ///
63 | ///
64 | public PackageVersionInfo CompareDifference(string localFolderPath, PackageVersionInfo romotePackageVersionInfo)
65 | {
66 | long totalLength = 0;
67 | List files = new List();
68 | CspParameters param = new CspParameters();
69 | param.KeyContainerName = SecretKey;
70 | DirectoryInfo directoryInfo = new DirectoryInfo(localFolderPath + "/");
71 | using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
72 | {
73 | using (MD5 md5 = new MD5CryptoServiceProvider())
74 | {
75 | foreach (var item in romotePackageVersionInfo.Files)
76 | {
77 | string filePath = System.IO.Path.Combine(directoryInfo.FullName, item.File.TrimStart('\\', '/'));
78 | FileInfo fileInfo = new FileInfo(filePath);
79 | if (File.Exists(filePath))
80 | {
81 | string emd5Str = ComputeEmd5(fileInfo, md5, rsa);
82 | if (emd5Str == item.Emd5)
83 | {
84 | continue;
85 | }
86 | }
87 | files.Add(item);
88 | totalLength += item.Length;
89 | }
90 | var diff = new PackageVersionInfo
91 | {
92 | Files = files.ToArray(),
93 | TotalLength = totalLength,
94 | PackageDate = romotePackageVersionInfo.PackageDate
95 | };
96 | return diff;
97 | }
98 | }
99 | }
100 |
101 | ///
102 | /// 计算本地指定目录的文件版本信息
103 | ///
104 | ///
105 | ///
106 | ///
107 | public PackageVersionInfo ComputeVersionInfo(string folderPath, params string[] ignoreFileNameKeys)
108 | {
109 | long totalLength = 0;
110 | List files = new List();
111 | CspParameters param = new CspParameters();
112 | param.KeyContainerName = SecretKey;
113 | DirectoryInfo directoryInfo = new DirectoryInfo(folderPath + "/");
114 | using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
115 | {
116 | using (MD5 md5 = new MD5CryptoServiceProvider())
117 | {
118 | RecursionFile(folderPath, null, filePath =>
119 | {
120 | if (ignoreFileNameKeys != null
121 | && ignoreFileNameKeys.Any(m => filePath.ToLower().Contains(m.ToLower())))
122 | {
123 | return;
124 | }
125 | FileInfo fileInfo = new FileInfo(filePath);
126 | string emd5Str = ComputeEmd5(fileInfo, md5, rsa);
127 | files.Add(new FileVersionInfo
128 | {
129 | File = fileInfo.FullName.Substring(directoryInfo.FullName.Length - 1),
130 | Emd5 = emd5Str,
131 | Length = fileInfo.Length
132 | });
133 | totalLength += fileInfo.Length;
134 | });
135 | return new PackageVersionInfo
136 | {
137 | Files = files.ToArray(),
138 | TotalLength = totalLength,
139 | PackageDate = DateTime.Now
140 | };
141 | }
142 | }
143 | }
144 | private static string ComputeEmd5(FileInfo fileInfo, MD5 md5, RSACryptoServiceProvider dsa)
145 | {
146 | using (FileStream fs = fileInfo.OpenRead())
147 | {
148 | byte[] md5Bytes = md5.ComputeHash(fs);
149 |
150 | byte[] hash;
151 | using (SHA1 sha1 = SHA1.Create())
152 | {
153 | hash = sha1.ComputeHash(md5Bytes);
154 | }
155 | RSAPKCS1SignatureFormatter DSAFormatter = new RSAPKCS1SignatureFormatter(dsa);
156 | DSAFormatter.SetHashAlgorithm("SHA1");
157 | byte[] encryptdata = DSAFormatter.CreateSignature(hash);
158 |
159 | return BytesToHexStr(encryptdata);
160 | }
161 | }
162 |
163 | ///
164 | /// 递归指定目录,针对每个符合扩展名的文件回调委托处理
165 | ///
166 | /// 要递归的目录
167 | /// 要求的文件扩展名数组,为空表示不限制扩展名,忽略大小写,需要包含“.”
168 | /// 回调委托
169 | private static void RecursionFile(string directoryString, string[] extensions, Action doFileCallBack)
170 | {
171 | if (extensions != null)
172 | extensions = extensions.Where(m => m != null).Select(m => m.ToLower()).ToArray();
173 | foreach (string fileName in Directory.GetFiles(directoryString))
174 | {
175 | if (extensions == null || extensions.Contains(Path.GetExtension(fileName).ToLower()))
176 | doFileCallBack(fileName);
177 | }
178 | foreach (string item in Directory.GetDirectories(directoryString))
179 | RecursionFile(item, extensions, doFileCallBack);
180 | }
181 |
182 | private static string BytesToHexStr(byte[] data)
183 | {
184 | StringBuilder sb = new StringBuilder();
185 | for (int i = 0; i < data.Length; i++)
186 | {
187 | sb.Append(data[i].ToString("x2"));
188 | }
189 | return sb.ToString();
190 | }
191 | }
192 |
193 | [XmlRoot("versionInfo")]
194 | public class PackageVersionInfo
195 | {
196 | [XmlArray("files")]
197 | [XmlArrayItem("file")]
198 | public FileVersionInfo[] Files { get; set; }
199 |
200 | [XmlAttribute("totalLength")]
201 | public long TotalLength { get; set; }
202 |
203 | [XmlAttribute("packageDate")]
204 | public DateTime PackageDate { get; set; }
205 | }
206 |
207 | [XmlRoot("versionInfo")]
208 | public class FileVersionInfo
209 | {
210 | [XmlAttribute("file")]
211 | public string File { get; set; }
212 | [XmlAttribute("emd5")]
213 | public string Emd5 { get; set; }
214 | [XmlAttribute("length")]
215 | public long Length { get; set; }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Shared/XmlSerializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace Zl.AutoUpgrade.Shared
8 | {
9 | static class XmlSerializer
10 | {
11 | public static byte[] ToBinary(object obj)
12 | {
13 | using (MemoryStream fs = new MemoryStream())
14 | {
15 | System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(obj.GetType());
16 | x.Serialize(fs, obj);
17 | fs.Flush();
18 | return fs.ToArray();
19 | }
20 | }
21 |
22 |
23 | public static T ToObject(byte[] data)
24 | {
25 | using (MemoryStream sr = new MemoryStream(data))
26 | {
27 | System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
28 | return (T)(x.Deserialize(sr));
29 | }
30 | }
31 |
32 | public static string ToString(object obj)
33 | {
34 | StringBuilder sb = new StringBuilder();
35 | using (StringWriter writer = new StringWriter(sb))
36 | {
37 | System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(obj.GetType());
38 | x.Serialize(writer, obj);
39 | writer.Flush();
40 | return sb.ToString();
41 | }
42 | }
43 |
44 | public static T ToObject(string dataString)
45 | {
46 | using (StringReader reader = new StringReader(dataString))
47 | {
48 | System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
49 | return (T)(x.Deserialize(reader));
50 | }
51 | }
52 |
53 | public static T Copy(T obj)
54 | {
55 | return ToObject(ToBinary(obj));
56 | }
57 | ///
58 | /// 从文件中读取 对应类型数据
59 | ///
60 | /// 类型
61 | /// 序列化实例
62 | /// 文件全路径
63 | /// 数据
64 | public static T LoadFromFile(string filePath)
65 | {
66 | using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
67 | {
68 | System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
69 | return (T)(x.Deserialize(stream));
70 | }
71 | }
72 |
73 | ///
74 | /// 将数据保存到指定的路径下
75 | ///
76 | /// 序列化实例
77 | /// 数据
78 | /// 文件全路径
79 | public static void SaveToFile(object obj, string filePath)
80 | {
81 | using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
82 | {
83 | System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(obj.GetType());
84 | x.Serialize(stream, obj);
85 | stream.Flush();
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Shared/Zl.AutoUpgrade.Shared.projitems:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 | true
6 | 1618087a-3cb4-45fa-84ff-1ea8b16bf7b6
7 |
8 |
9 | Zl.AutoUpgrade.Shared
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.Shared/Zl.AutoUpgrade.Shared.shproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1618087a-3cb4-45fa-84ff-1ea8b16bf7b6
5 | 14.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.VersionInfoBuilder/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.VersionInfoBuilder/Program.cs:
--------------------------------------------------------------------------------
1 | using Args.Help.Formatters;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Text;
9 | using Zl.AutoUpgrade.Shared;
10 |
11 | namespace Zl.AutoUpgrade.VersionInfoBuilder
12 | {
13 | class Program
14 | {
15 | private const string versionFileName = "versionInfo.xml";
16 | static void Main(string[] args)
17 | {
18 | try
19 | {
20 | var definition = Args.Configuration.Configure();
21 | var command = definition.CreateAndBind(args);
22 | if (command.Help != null)
23 | {
24 | var help = new Args.Help.HelpProvider().GenerateModelHelp(definition);
25 | var f = new ConsoleHelpFormatter(80, 1, 5);
26 | Console.WriteLine(f.GetHelp(help));
27 | return;
28 | }
29 | Console.WriteLine($"正在生成...");
30 | Console.WriteLine($"目标文件夹:{command.TargetFolder}");
31 | Console.WriteLine($"秘钥:{command.SecretKey}");
32 | Console.WriteLine($"忽略文件:{ ((command.Ignore == null || command.Ignore.Count == 0) ? "无" : string.Join(", ", command.Ignore))}");
33 | VersionService versionService = new VersionService(command.SecretKey);
34 | if (command.Ignore == null)
35 | command.Ignore = new List(2);
36 | command.Ignore.Add(Path.GetFileNameWithoutExtension(typeof(Program).Assembly.Location));
37 | command.Ignore.Add(versionFileName);
38 | command.Ignore.Add("Zl.AutoUpgrade.Core");
39 | PackageVersionInfo info = versionService.ComputeVersionInfo(command.TargetFolder,
40 | command.Ignore.ToArray());
41 | XmlSerializer.SaveToFile(info, System.IO.Path.Combine(command.TargetFolder, versionFileName));
42 | Console.WriteLine($"生成完毕.");
43 | }
44 | catch (Exception exc)
45 | {
46 | Console.ForegroundColor = ConsoleColor.Red;
47 | Console.WriteLine(exc);
48 | Console.ResetColor();
49 | }
50 | }
51 |
52 | [System.ComponentModel.Description("升级包版本文件生成器工具.")]
53 | class CommandObject
54 | {
55 | [Description("要生成版本文件的目标文件夹,生成版本文件后的文件夹才可作为升级包供升级")]
56 | public string TargetFolder { get; set; } = AppDomain.CurrentDomain.BaseDirectory;
57 | [Description("版本信息秘钥,客户端只有与本生成器使用的秘钥一致时才可正常升级本生成器生成的版本升级包")]
58 | public string SecretKey { get; set; } = "Zl.AutoUpgrade.SecretKey";
59 |
60 | [Description("目标文件夹中要忽略的文件,多个用空格间隔")]
61 | public List Ignore { get; set; }
62 |
63 | [Description("查看帮助")]
64 | public string Help { get; set; }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.VersionInfoBuilder/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Zl.AutoUpgrade.VersionInfoBuilder")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 |
12 | // 将 ComVisible 设置为 false 会使此程序集中的类型
13 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
14 | //请将此类型的 ComVisible 特性设置为 true。
15 | [assembly: ComVisible(false)]
16 |
17 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
18 | [assembly: Guid("bf0bc324-a831-4316-a64a-f05bc2346c4a")]
19 |
20 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.VersionInfoBuilder/Zl.AutoUpgrade.VersionInfoBuilder.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BF0BC324-A831-4316-A64A-F05BC2346C4A}
8 | Exe
9 | Zl.AutoUpgrade.VersionInfoBuilder
10 | VersionInfoBuilder
11 | v4.0
12 | 512
13 |
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | app.ico
37 |
38 |
39 |
40 | ..\packages\Args.1.1.2\lib\Net40\Args.dll
41 |
42 |
43 | ..\packages\Costura.Fody.1.6.2\lib\portable-net+sl+win+wpa+wp\Costura.dll
44 | False
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Properties\ComponentInfo.cs
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.VersionInfoBuilder/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenglo/AutoUpgrade/5d529056570466c50ca2c95987f16a3364ae2d35/src/Zl.AutoUpgrade.VersionInfoBuilder/app.ico
--------------------------------------------------------------------------------
/src/Zl.AutoUpgrade.VersionInfoBuilder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------