返回提交历史
Modified
XFEToolBox.Client.Installer/XFEToolBox.Client.Installer.csproj
+1
-1
Modified
XFEToolBox/Utilities/ToolProjectRunService.cs
+50
-4
Modified
XFEToolBox/XFEToolBox.Client.csproj
+1
-1
XFEstudio/XFEToolBox
升级版本号至 1.1.1,优化进程启动与异常处理
- XFEToolBox.Client 和 Installer 版本号升级至 1.1.1 - ToolProjectRunService.cs 优化进程启动与异常处理逻辑 - 增加 2 秒启动观测窗口,异常时收集输出并返回详细信息 - 启动 dotnet 进程时重定向标准输出和错误输出 - 优化 CleanupAfterExitAsync,确保异步读取输出后释放资源 - 新增 FormatRuntimeFailure 方法,格式化启动失败信息 - 修正主题资源路径,统一引用 XFEToolBox.WpfCore 资源
60b4b45
代码差异
3 个文件
+52
-6
@@ -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>
@@ -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)
@@ -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>