XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEToolBox

升级版本号至 1.1.1,优化进程启动与异常处理

- XFEToolBox.Client 和 Installer 版本号升级至 1.1.1 - ToolProjectRunService.cs 优化进程启动与异常处理逻辑 - 增加 2 秒启动观测窗口,异常时收集输出并返回详细信息 - 启动 dotnet 进程时重定向标准输出和错误输出 - 优化 CleanupAfterExitAsync,确保异步读取输出后释放资源 - 新增 FormatRuntimeFailure 方法,格式化启动失败信息 - 修正主题资源路径,统一引用 XFEToolBox.WpfCore 资源

60b4b45
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

3 个文件 +52 -6
Modified XFEToolBox.Client.Installer/XFEToolBox.Client.Installer.csproj +1 -1
@@ -9,7 +9,7 @@
9 9 <ApplicationManifest>app.manifest</ApplicationManifest>
10 10 <ApplicationIcon>Resources\Icon\Icon.ico</ApplicationIcon>
11 11 <AssemblyName>Installer</AssemblyName>
12 <Version>1.1.0</Version>
12 <Version>1.1.1</Version>
13 13 </PropertyGroup>
14 14
15 15 <ItemGroup>
Modified XFEToolBox/Utilities/ToolProjectRunService.cs +50 -4
@@ -15,6 +15,7 @@ internal static class ToolProjectRunService
15 15 {
16 16 private const int MaximumPackageEntryCount = 512;
17 17 private const long MaximumExtractedPackageBytes = 128L * 1024 * 1024;
18 private static readonly TimeSpan RuntimeStartupObservationWindow = TimeSpan.FromSeconds(2);
18 19 private static readonly JsonSerializerOptions ManifestJsonOptions = new(JsonSerializerDefaults.Web);
19 20
20 21 public static async Task<ToolRunResult> BuildAsync(
@@ -158,12 +159,36 @@ internal static class ToolProjectRunService
158 159 {
159 160 WorkingDirectory = workspaceRoot,
160 161 UseShellExecute = false,
161 CreateNoWindow = true
162 CreateNoWindow = true,
163 RedirectStandardOutput = true,
164 RedirectStandardError = true
162 165 };
163 166 runInfo.ArgumentList.Add(runtimeAssembly);
164 167 var runtimeProcess = Process.Start(runInfo)
165 168 ?? throw new InvalidOperationException("工具运行进程启动失败。");
166 _ = CleanupAfterExitAsync(runtimeProcess, runtimeRoot, temporaryWorkspaceRoot);
169 var runtimeStandardOutputTask = runtimeProcess.StandardOutput.ReadToEndAsync();
170 var runtimeStandardErrorTask = runtimeProcess.StandardError.ReadToEndAsync();
171 var exitTask = runtimeProcess.WaitForExitAsync(cancellationToken);
172 var startupObservationTask = Task.Delay(RuntimeStartupObservationWindow, cancellationToken);
173 if (await Task.WhenAny(exitTask, startupObservationTask) == exitTask)
174 {
175 await exitTask;
176 var runtimeOutput = (await runtimeStandardOutputTask) + Environment.NewLine + (await runtimeStandardErrorTask);
177 var exitCode = runtimeProcess.ExitCode;
178 runtimeProcess.Dispose();
179 TryDeleteDirectory(runtimeRoot);
180 if (temporaryWorkspaceRoot is not null)
181 TryDeleteDirectory(temporaryWorkspaceRoot);
182 return new ToolRunResult(false, FormatRuntimeFailure(runtimeOutput, exitCode), null);
183 }
184
185 cancellationToken.ThrowIfCancellationRequested();
186 _ = CleanupAfterExitAsync(
187 runtimeProcess,
188 runtimeRoot,
189 temporaryWorkspaceRoot,
190 runtimeStandardOutputTask,
191 runtimeStandardErrorTask);
167 192 return new ToolRunResult(true, "工具已完成编译并在独立窗口中运行。", runtimeProcess.Id);
168 193 }
169 194 catch (Exception exception)
@@ -237,7 +262,7 @@ internal static class ToolProjectRunService
237 262 : manifest.Subtitle.Trim());
238 263 var iconPath = JsonSerializer.Serialize(toolIconPath);
239 264 var themeResourceUri = JsonSerializer.Serialize(
240 $"pack://application:,,,/{hostAssemblyName};component/Resources/Style/ToolThemeResources.xaml");
265 "pack://application:,,,/XFEToolBox.WpfCore;component/Resources/Style/ToolThemeResources.xaml");
241 266 var mainStyleResourceUri = JsonSerializer.Serialize(
242 267 $"pack://application:,,,/{hostAssemblyName};component/Resources/Style/MainStyle.xaml");
243 268 var defaultIconResourceUri = JsonSerializer.Serialize(
@@ -609,11 +634,14 @@ internal static class ToolProjectRunService
609 634 private static async Task CleanupAfterExitAsync(
610 635 Process process,
611 636 string runtimeRoot,
612 string? temporaryWorkspaceRoot)
637 string? temporaryWorkspaceRoot,
638 Task<string> standardOutputTask,
639 Task<string> standardErrorTask)
613 640 {
614 641 try
615 642 {
616 643 await process.WaitForExitAsync();
644 await Task.WhenAll(standardOutputTask, standardErrorTask);
617 645 process.Dispose();
618 646 }
619 647 catch
@@ -902,6 +930,24 @@ internal static class ToolProjectRunService
902 930 return "工具编译未通过:\n" + string.Join(Environment.NewLine, importantLines);
903 931 }
904 932
933 private static string FormatRuntimeFailure(string output, int exitCode)
934 {
935 var importantLines = output.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)
936 .Where(line => line.Contains("Exception", StringComparison.OrdinalIgnoreCase)
937 || line.Contains("error", StringComparison.OrdinalIgnoreCase)
938 || line.Contains("错误", StringComparison.OrdinalIgnoreCase)
939 || line.Contains("找不到", StringComparison.OrdinalIgnoreCase))
940 .Take(8)
941 .ToArray();
942 if (importantLines.Length == 0)
943 importantLines = output.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries).TakeLast(8).ToArray();
944
945 var details = importantLines.Length == 0
946 ? "工具进程在窗口显示前意外退出。"
947 : string.Join(Environment.NewLine, importantLines);
948 return $"工具启动失败(退出代码 {exitCode}):\n{details}";
949 }
950
905 951 private static string EscapeXml(string value) => SecurityElement.Escape(value) ?? value;
906 952
907 953 private static void TryDeleteDirectory(string path)
Modified XFEToolBox/XFEToolBox.Client.csproj +1 -1
@@ -7,7 +7,7 @@
7 7 <ImplicitUsings>enable</ImplicitUsings>
8 8 <UseWPF>true</UseWPF>
9 9 <ApplicationIcon>Resources\Icon\XFEToolBoxIcon.ico</ApplicationIcon>
10 <Version>1.1.0</Version>
10 <Version>1.1.1</Version>
11 11 <AssemblyTitle>XFEToolBox</AssemblyTitle>
12 12 <AssemblyName>XFEToolBox</AssemblyName>
13 13 </PropertyGroup>