diff --git a/AutoUpdate/AutoUpdate.sln b/AutoUpdate/AutoUpdate.sln
index e58e391..5d58408 100644
--- a/AutoUpdate/AutoUpdate.sln
+++ b/AutoUpdate/AutoUpdate.sln
@@ -4,6 +4,8 @@ VisualStudioVersion = 17.13.35731.43
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoUpdate", "AutoUpdate\AutoUpdate.csproj", "{7851792C-7CFE-4748-A712-974AE110E2D3}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoUpdateServer", "AutoUpdateServer\AutoUpdateServer.csproj", "{1BDC940C-E1EC-4D8F-A374-CC360C52EEBB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -14,6 +16,10 @@ Global
{7851792C-7CFE-4748-A712-974AE110E2D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7851792C-7CFE-4748-A712-974AE110E2D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7851792C-7CFE-4748-A712-974AE110E2D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1BDC940C-E1EC-4D8F-A374-CC360C52EEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1BDC940C-E1EC-4D8F-A374-CC360C52EEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1BDC940C-E1EC-4D8F-A374-CC360C52EEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1BDC940C-E1EC-4D8F-A374-CC360C52EEBB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/AutoUpdate/AutoUpdate/App.xaml b/AutoUpdate/AutoUpdate/App.xaml
index 91d23de..e1a6071 100644
--- a/AutoUpdate/AutoUpdate/App.xaml
+++ b/AutoUpdate/AutoUpdate/App.xaml
@@ -2,8 +2,73 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AutoUpdate"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
StartupUri="MainWindow.xaml">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pack://application:,,,/Lmes;component/字体/MiSans-Normal.ttf#misans
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AutoUpdate/AutoUpdate/AssemblyInfo.cs b/AutoUpdate/AutoUpdate/AssemblyInfo.cs
index cc29e7f..ac816f6 100644
--- a/AutoUpdate/AutoUpdate/AssemblyInfo.cs
+++ b/AutoUpdate/AutoUpdate/AssemblyInfo.cs
@@ -1,10 +1,11 @@
+using System.Reflection;
using System.Windows;
-[assembly:ThemeInfo(
- ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
- //(used if a resource is not found in the page,
- // or application resource dictionaries)
- ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
- //(used if a resource is not found in the page,
- // app, or any theme specific resource dictionaries)
-)]
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/AutoUpdate/AutoUpdate/AutoUpdate.csproj b/AutoUpdate/AutoUpdate/AutoUpdate.csproj
index defb4d1..1a858a6 100644
--- a/AutoUpdate/AutoUpdate/AutoUpdate.csproj
+++ b/AutoUpdate/AutoUpdate/AutoUpdate.csproj
@@ -8,4 +8,11 @@
true
+
+
+
+
+
+
+
diff --git a/AutoUpdate/AutoUpdate/LmesApi.cs b/AutoUpdate/AutoUpdate/LmesApi.cs
new file mode 100644
index 0000000..8b040f9
--- /dev/null
+++ b/AutoUpdate/AutoUpdate/LmesApi.cs
@@ -0,0 +1,102 @@
+using System.IO;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Net.Http.Json;
+using Path = System.IO.Path;
+
+namespace AutoUpdate
+{
+ public class LmesApi
+ {
+ public readonly HttpClient httpClient = new();
+ public LmesApi(string 基地址)
+ {
+ httpClient.BaseAddress = new Uri(基地址);
+ }
+
+ #region 更新程序
+ public async Task 更新客户端程序()
+ {
+ try
+ {
+ // 获取当前版本信息(从程序集或配置文件中读取)
+ var versionManager = new VersionManager();
+ var currentVersion = versionManager.GetCurrentVersion();
+
+ // 检查最新版本
+ var latestVersion = await 获取最新版本();
+ if (latestVersion == null || latestVersion.Version == currentVersion)
+ {
+ return currentVersion; // 无需更新
+ }
+
+ // 下载新版本
+ var downloadPath = await 下载新版本(latestVersion);
+ if (string.IsNullOrEmpty(downloadPath))
+ {
+ throw new Exception("下载更新包失败");
+ }
+
+ // 验证下载文件的CRC
+ if (!VerifyCRC(downloadPath, latestVersion.CRC))
+ {
+ throw new Exception("文件校验失败,可能已损坏");
+ }
+
+ // 使用新的更新管理器
+ var updater = new UpdateManager();
+ await updater.ExtractAndUpdate(downloadPath, latestVersion.Version);
+ return latestVersion.Version;
+ }
+ catch (Exception ex)
+ {
+ // 记录错误日志
+ //日志写入.写入($"更新失败: {ex.Message}");
+ throw;
+ }
+ }
+
+ private async Task 获取最新版本()
+ {
+ var response = await httpClient.GetAsync("api/自动更新/获取最新版本信息");
+ if (!response.IsSuccessStatusCode)
+ {
+ return null;
+ }
+ return await response.Content.ReadFromJsonAsync();
+ }
+
+ private async Task 下载新版本(VersionInfo versionInfo)
+ {
+ var downloadPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updates", versionInfo.FileName);
+
+ using var response = await httpClient.GetAsync($"api/自动更新/下载指定版本/{versionInfo.FileName}");
+ if (!response.IsSuccessStatusCode)
+ {
+ return null;
+ }
+
+ using var fileStream = new FileStream(downloadPath, FileMode.Create);
+ await response.Content.CopyToAsync(fileStream);
+
+ return downloadPath;
+ }
+
+ private bool VerifyCRC(string filePath, string expectedCRC)
+ {
+ using var fs = System.IO.File.OpenRead(filePath);
+ using var sha = System.Security.Cryptography.SHA256.Create();
+ var hash = sha.ComputeHash(fs);
+ var actualCRC = BitConverter.ToString(hash).Replace("-", "");
+
+ return string.Equals(actualCRC, expectedCRC, StringComparison.OrdinalIgnoreCase);
+ }
+ public class VersionInfo
+ {
+ public string Version { get; set; }
+ public string CRC { get; set; }
+ public string FileName { get; set; }
+ }
+ #endregion
+ }
+}
diff --git a/AutoUpdate/AutoUpdate/MainWindow.xaml b/AutoUpdate/AutoUpdate/MainWindow.xaml
index 379fb3a..2250ef9 100644
--- a/AutoUpdate/AutoUpdate/MainWindow.xaml
+++ b/AutoUpdate/AutoUpdate/MainWindow.xaml
@@ -1,12 +1,13 @@
-
+ Title="MainWindow" Height="450" Width="800" Loaded="MetroWindow_Loaded">
-
-
+
diff --git a/AutoUpdate/AutoUpdate/MainWindow.xaml.cs b/AutoUpdate/AutoUpdate/MainWindow.xaml.cs
index 8e86fe9..1e05afb 100644
--- a/AutoUpdate/AutoUpdate/MainWindow.xaml.cs
+++ b/AutoUpdate/AutoUpdate/MainWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System.Text;
+using System.IO;
+using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
@@ -8,16 +9,47 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
+using MahApps.Metro.Controls;
+using Path = System.IO.Path;
namespace AutoUpdate;
///
/// Interaction logic for MainWindow.xaml
///
-public partial class MainWindow : Window
+public partial class MainWindow : MetroWindow
{
- public MainWindow()
- {
- InitializeComponent();
- }
-}
\ No newline at end of file
+ private LmesApi lmesApi;
+ public MainWindow()
+ {
+ InitializeComponent();
+ lmesApi = new LmesApi(系统参数.设置.Lmes连接参数.LMES地址);
+ }
+
+ private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
+ {
+
+ _ = 自动更新程序();
+ }
+
+ private async Task 自动更新程序()
+ {
+ var 本地目录 = AppDomain.CurrentDomain.BaseDirectory;
+ var 临时更新目录 = Path.Combine(本地目录, "Updates");
+
+ // 确保临时更新目录存在
+ if (!Directory.Exists(临时更新目录))
+ {
+ Directory.CreateDirectory(临时更新目录);
+ }
+ try
+ {
+ Title = "当前版本信息:" + await lmesApi.更新客户端程序();
+ }
+ catch (Exception ex)
+ {
+ // 更新失败,但允许程序继续运行
+ //日志写入.写入($"检查更新失败: {ex.Message}");
+ }
+ }
+}
diff --git a/AutoUpdate/AutoUpdate/UpdateManager.cs b/AutoUpdate/AutoUpdate/UpdateManager.cs
new file mode 100644
index 0000000..5d13004
--- /dev/null
+++ b/AutoUpdate/AutoUpdate/UpdateManager.cs
@@ -0,0 +1,130 @@
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Windows;
+
+namespace AutoUpdate
+{
+ public class UpdateManager
+ {
+ private readonly string _programPath;
+ private readonly string _updatePath;
+ private readonly string _backupPath;
+ private readonly VersionManager _versionManager;
+
+ public UpdateManager()
+ {
+ // 程序主目录
+ _programPath = AppDomain.CurrentDomain.BaseDirectory;
+ // 更新文件夹
+ _updatePath = Path.Combine(_programPath, "Update");
+ // 备份文件夹
+ _backupPath = Path.Combine(_programPath, "Backup");
+ _versionManager = new VersionManager();
+ }
+
+ public async Task ExtractAndUpdate(string zipPath, string newVersion)
+ {
+ try
+ {
+ // 准备更新目录
+ if (Directory.Exists(_updatePath))
+ Directory.Delete(_updatePath, true);
+ Directory.CreateDirectory(_updatePath);
+
+ // 解压新版本到更新目录
+ await Task.Run(() => ZipFile.ExtractToDirectory(zipPath, _updatePath));
+
+
+
+
+ // 创建更新批处理文件
+ string batchContent = @"
+@echo off
+:: 等待原程序退出
+timeout /t 1 /nobreak
+
+:: 复制新文件
+xcopy /Y /E ""%~dp0Update\*.*"" ""%~dp0.""
+
+:: 删除更新文件夹
+rd /S /Q ""%~dp0Update""
+
+:: 清理 Updates 文件夹
+if exist ""%~dp0Updates"" (
+ rd /S /Q ""%~dp0Updates""
+)
+
+:: 启动程序
+start """" ""%~dp0LMES.exe""
+
+:: 删除自身
+del ""%~f0""
+";
+
+ string batchPath = Path.Combine(_programPath, "update.bat");
+ await File.WriteAllTextAsync(batchPath, batchContent);
+
+ // 启动更新批处理并退出程序
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = batchPath,
+ UseShellExecute = true,
+ CreateNoWindow = true,
+ Verb = "runas", // 请求管理员权限
+ };
+ Process.Start(startInfo);
+ // 更新版本文件
+ _versionManager.UpdateVersion(newVersion);
+ // 退出应用程序
+ Application.Current.Shutdown();
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"更新失败: {ex.Message}");
+ }
+ }
+ }
+
+ public class VersionManager
+ {
+ private readonly string _versionFilePath;
+
+ public VersionManager()
+ {
+ _versionFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "version.txt");
+ }
+
+ public string GetCurrentVersion()
+ {
+ // First try to read from version file
+ if (File.Exists(_versionFilePath))
+ {
+ try
+ {
+ return File.ReadAllText(_versionFilePath).Trim();
+ }
+ catch (Exception ex)
+ {
+ //日志写入.写入($"读取版本文件失败: {ex.Message}");
+ }
+ }
+
+ // Fall back to assembly version if file doesn't exist
+ return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ }
+
+ public void UpdateVersion(string newVersion)
+ {
+ try
+ {
+ File.WriteAllText(_versionFilePath, newVersion);
+ }
+ catch (Exception ex)
+ {
+ //日志写入.写入($"写入版本文件失败: {ex.Message}");
+ throw;
+ }
+ }
+ }
+}
diff --git a/AutoUpdate/AutoUpdate/系统参数.cs b/AutoUpdate/AutoUpdate/系统参数.cs
new file mode 100644
index 0000000..10ebfa3
--- /dev/null
+++ b/AutoUpdate/AutoUpdate/系统参数.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AutoUpdate
+{
+ public class 系统参数
+ {
+ public static 设置类 设置 { get; set; } = new();
+ }
+
+ public class 设置类
+ {
+ public Lmes连接参数类 Lmes连接参数 { get; set; } = new();
+ }
+
+ public class Lmes连接参数类
+ {
+ public string LMES地址 { get; set; } = @"http://127.0.0.1:5000/";
+ }
+}
diff --git a/AutoUpdate/AutoUpdateServer/AutoUpdateServer.csproj b/AutoUpdate/AutoUpdateServer/AutoUpdateServer.csproj
new file mode 100644
index 0000000..f011944
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/AutoUpdateServer.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/AutoUpdate/AutoUpdateServer/AutoUpdateServer.http b/AutoUpdate/AutoUpdateServer/AutoUpdateServer.http
new file mode 100644
index 0000000..e008039
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/AutoUpdateServer.http
@@ -0,0 +1,6 @@
+@AutoUpdateServer_HostAddress = http://localhost:5062
+
+GET {{AutoUpdateServer_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/AutoUpdate/AutoUpdateServer/Controllers/自动更新Controller.cs b/AutoUpdate/AutoUpdateServer/Controllers/自动更新Controller.cs
new file mode 100644
index 0000000..b43423c
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/Controllers/自动更新Controller.cs
@@ -0,0 +1,133 @@
+using System.ComponentModel;
+using System.IO.Compression;
+using Microsoft.AspNetCore.Cors;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Lmes服务端.Controllers
+{
+ // 版本信息模型
+ public class VersionInfo
+ {
+ public string Version { get; set; }
+ public string CRC { get; set; }
+ public string FileName { get; set; }
+ }
+ [EnableCors("AllowAll")]
+ [Route("api/[controller]")]
+ [ApiController]
+ public class 自动更新Controller : ControllerBase
+ {
+ private string 存储路径 { get; set; }
+
+ public 自动更新Controller()
+ {
+ // 设置版本文件存储路径
+ 存储路径 = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "Lmes_1.0",
+ "VersionInfo"
+ );
+
+ // 确保目录存在
+ if (!Directory.Exists(存储路径))
+ {
+ Directory.CreateDirectory(存储路径);
+ }
+ }
+
+ // 获取最新版本信息
+ [HttpGet("获取最新版本信息")]
+ public ActionResult GetLatestVersion()
+ {
+ try
+ {
+ var files = Directory.GetFiles(存储路径, "*.zip");
+ if (!files.Any())
+ {
+ return NotFound("未找到任何版本文件");
+ }
+
+ // 获取最新的版本文件
+ var latestFile = files.OrderByDescending(f => f).First();
+ var fileName = Path.GetFileNameWithoutExtension(latestFile);
+
+ // 计算文件的CRC值
+ string crc;
+ using (var fs = System.IO.File.OpenRead(latestFile))
+ {
+ using var sha = System.Security.Cryptography.SHA256.Create();
+ var hash = sha.ComputeHash(fs);
+ crc = BitConverter.ToString(hash).Replace("-", "");
+ }
+
+ return new VersionInfo
+ {
+ Version = fileName.Split("--")[0],
+ CRC = crc,
+ FileName = Path.GetFileName(latestFile)
+ };
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, $"获取版本信息失败: {ex.Message}");
+ }
+ }
+
+ // 上传新版本
+ [HttpPost("上传新版本")]
+ public async Task UploadVersion(IFormFile file)
+ {
+ try
+ {
+ var fileName = file.FileName;
+ var filePath = Path.Combine(存储路径, fileName);
+
+ using (var stream = new FileStream(filePath, FileMode.Create))
+ {
+ await file.CopyToAsync(stream);
+ }
+
+ // 验证上传的文件是否为有效的ZIP文件
+ try
+ {
+ using (var archive = ZipFile.OpenRead(filePath))
+ {
+ // 检查是否包含必要的文件
+ if (!archive.Entries.Any(e => e.Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)))
+ {
+ System.IO.File.Delete(filePath);
+ return BadRequest("ZIP文件中未找到可执行文件");
+ }
+ }
+ }
+ catch
+ {
+ System.IO.File.Delete(filePath);
+ return BadRequest("上传的文件不是有效的ZIP文件");
+ }
+
+ return Ok("文件上传成功");
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, $"文件上传失败: {ex.Message}");
+ }
+ }
+
+ // 下载指定版本
+ [HttpGet("下载指定版本/{fileName}")]
+ public IActionResult DownloadVersion(string fileName)
+ {
+ var filePath = Path.Combine(存储路径, fileName);
+
+ if (!System.IO.File.Exists(filePath))
+ {
+ return NotFound("指定的版本文件不存在");
+ }
+
+ var fileStream = System.IO.File.OpenRead(filePath);
+ return File(fileStream, "application/zip", fileName);
+ }
+ }
+}
diff --git a/AutoUpdate/AutoUpdateServer/Program.cs b/AutoUpdate/AutoUpdateServer/Program.cs
new file mode 100644
index 0000000..83b48e4
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/Program.cs
@@ -0,0 +1,53 @@
+
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+
+namespace AutoUpdateServer
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ builder.Services.AddCors(options =>
+ {
+ options.AddPolicy("AllowAll", builder =>
+ {
+ builder.AllowAnyOrigin()
+ .AllowAnyHeader()
+ .AllowAnyMethod();
+ });
+ });
+ builder.Services.AddControllers();
+ // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+ builder.Services.AddEndpointsApiExplorer();
+ builder.Services.AddSwaggerGen();
+ builder.Services.AddLogging();
+ builder.Services.Configure(options =>
+ {
+ options.Limits.MaxRequestBodySize = 1024 * 1024 * 1024; // 100 MB
+ });
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseAuthorization();
+
+ app.UseCors("AllowAll");
+
+ app.UseSwagger();
+ app.UseSwaggerUI();
+
+ app.MapControllers();
+
+ app.Run();
+ }
+ }
+}
diff --git a/AutoUpdate/AutoUpdateServer/Properties/launchSettings.json b/AutoUpdate/AutoUpdateServer/Properties/launchSettings.json
new file mode 100644
index 0000000..135ac87
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/Properties/launchSettings.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5062",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "https://localhost:7116;http://localhost:5062",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/AutoUpdate/AutoUpdateServer/appsettings.Development.json b/AutoUpdate/AutoUpdateServer/appsettings.Development.json
new file mode 100644
index 0000000..0268711
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/appsettings.Development.json
@@ -0,0 +1,15 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "Kestrel": {
+ "Endpoints": {
+ "Http": {
+ "Url": "http://*:5000"
+ }
+ }
+ }
+}
diff --git a/AutoUpdate/AutoUpdateServer/appsettings.json b/AutoUpdate/AutoUpdateServer/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/AutoUpdate/AutoUpdateServer/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}