From 08714df731f7bbf83be6961a09bd5b45d63ebab3 Mon Sep 17 00:00:00 2001 From: Blank Date: Sun, 25 Oct 2026 17:20:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(capability-hosting):=20=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=89=AB=E6=8F=8F=E5=A4=B1=E8=B4=A5=E7=BA=B3=E5=85=A5?= =?UTF-8?q?=E8=A3=85=E9=85=8D=E9=97=AE=E9=A2=98=E6=B8=85=E5=8D=95=E5=B9=B6?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E5=8A=A0=E8=BD=BD=E5=8E=9F=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CollectModuleTypes 在 ReflectionTypeLoadException 时原先抛 InvalidOperationException,Compose 只捕获 CapabilityAssemblyException, 导致 RenderFailures 不打 Error 且仅剩失败个数、丢失具体原因。 改为抛 CapabilityAssemblyException:首条为程序集定位信息,其后逐条 保留 LoaderExceptions 的 Message;同步调整扫描失败用例断言。 --- .../CapabilityAssembly.cs | 17 +++++++++++++++-- .../CapabilityDeploymentDiscoveryTests.cs | 9 ++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs b/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs index 0a412721e..6cf4b12a4 100644 --- a/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs +++ b/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs @@ -47,7 +47,8 @@ public static class CapabilityAssembly /// 扫描指定程序集集合(缺省 = 当前 AppDomain 全部已加载程序集;同 Id 多实现 fail-fast)。 /// /// 程序集集合(null = 全部已加载)。 - /// 发现的能力模块(按程序集名 + 类型名稳定排序;同 Id 多实现抛 )。 + /// 发现的能力模块(按程序集名 + 类型名稳定排序;同 Id 多实现抛 ; + /// 程序集类型无法完整加载抛 )。 public static IReadOnlyList DiscoverModules(IEnumerable assemblies = null) { var targetAssemblies = assemblies ?? AppDomain.CurrentDomain.GetAssemblies(); @@ -144,7 +145,19 @@ private static void CollectModuleTypes(Assembly assembly, List moduleTypes catch (ReflectionTypeLoadException exception) { // 命中命名约定的能力包类型无法完整加载(如依赖缺失)= 部署残缺——带定位信息 fail-fast,不再静默跳过。 - throw new InvalidOperationException(string.Format(LocalizationService.GetString(Localization.Keys.Capability.Hosting.ModuleTypeScanFailed), assembly.GetName().Name, exception.LoaderExceptions == null ? 0 : exception.LoaderExceptions.Length)); + // 抛 CapabilityAssemblyException:组合入口统一经 RenderFailures 逐条打 Error,首条为程序集定位,其后逐条保留底层加载原因。 + var loaderExceptions = exception.LoaderExceptions ?? Array.Empty(); + var problems = new List(loaderExceptions.Length + 1); + problems.Add(string.Format(LocalizationService.GetString(Localization.Keys.Capability.Hosting.ModuleTypeScanFailed), assembly.GetName().Name, loaderExceptions.Length)); + foreach (var loaderException in loaderExceptions) + { + if (loaderException != null) + { + problems.Add(loaderException.Message); + } + } + + throw new CapabilityAssemblyException(problems); } foreach (var type in types) diff --git a/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs b/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs index 106e1424e..69ca7c14c 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs @@ -89,7 +89,8 @@ public void LoadDeploymentAssemblies_CorruptArtifact_FailsFastWithProblems() } /// - /// 类型无法完整加载的能力包(依赖缺失)不再静默跳过:带程序集名定位信息 fail-fast。 + /// 类型无法完整加载的能力包(依赖缺失)不再静默跳过:抛 , + /// 首条问题带程序集名定位,其后逐条保留底层类型加载原因(组合入口据此经 RenderFailures 一次报全)。 /// [Fact] public void DiscoverModules_UnloadableTypes_FailsFastWithAssemblyName() @@ -100,8 +101,10 @@ public void DiscoverModules_UnloadableTypes_FailsFastWithAssemblyName() { var assembly = Assembly.LoadFrom(path); - var exception = Assert.Throws(() => CapabilityAssembly.DiscoverModules(new[] { assembly, })); - Assert.Contains("CapabilityDeploymentScanProbe.Broken", exception.Message); + var exception = Assert.Throws(() => CapabilityAssembly.DiscoverModules(new[] { assembly, })); + Assert.Contains("CapabilityDeploymentScanProbe.Broken", exception.Problems[0]); + Assert.True(exception.Problems.Count > 1); + Assert.Contains(exception.Problems.Skip(1), problem => problem.Contains("CapabilityDeploymentScanProbe.Missing")); } finally { From cca6192016028e712e2fb95ac5fd75c8d0155757 Mon Sep 17 00:00:00 2001 From: Blank Date: Sun, 25 Oct 2026 17:26:43 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(capability-hosting):=20=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=89=AB=E6=8F=8F=E5=A4=B1=E8=B4=A5=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E5=8E=9F=E5=A7=8B=20ReflectionTypeLoadExcept?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CapabilityAssemblyException 新增接收内部异常的构造函数,CollectModuleTypes 重新封装时传入原始异常,调用方可检查原始堆栈与 LoaderExceptions 对象; Problems 输出保持不变。 --- .../CapabilityAssembly.cs | 2 +- .../CapabilityAssemblyException.cs | 11 +++++++++++ .../Online/CapabilityDeploymentDiscoveryTests.cs | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs b/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs index 6cf4b12a4..92d5dac2b 100644 --- a/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs +++ b/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssembly.cs @@ -157,7 +157,7 @@ private static void CollectModuleTypes(Assembly assembly, List moduleTypes } } - throw new CapabilityAssemblyException(problems); + throw new CapabilityAssemblyException(problems, exception); } foreach (var type in types) diff --git a/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssemblyException.cs b/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssemblyException.cs index 7cbcd72a1..2c30b0395 100644 --- a/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssemblyException.cs +++ b/Capability/GameFrameX.Capability.Hosting.Core/CapabilityAssemblyException.cs @@ -50,6 +50,17 @@ public CapabilityAssemblyException(IReadOnlyList problems) Problems = problems; } + /// + /// 初始化 (保留触发问题的原始异常,供诊断堆栈与底层异常对象)。 + /// + /// 全部问题条目(已本地化;至少一条)。 + /// 触发问题的原始异常。 + public CapabilityAssemblyException(IReadOnlyList problems, Exception innerException) + : base(BuildMessage(problems), innerException) + { + Problems = problems; + } + /// /// 获取全部问题条目(已本地化)。 /// diff --git a/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs b/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs index 69ca7c14c..40ad77c9f 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilityDeploymentDiscoveryTests.cs @@ -105,6 +105,7 @@ public void DiscoverModules_UnloadableTypes_FailsFastWithAssemblyName() Assert.Contains("CapabilityDeploymentScanProbe.Broken", exception.Problems[0]); Assert.True(exception.Problems.Count > 1); Assert.Contains(exception.Problems.Skip(1), problem => problem.Contains("CapabilityDeploymentScanProbe.Missing")); + Assert.IsType(exception.InnerException); } finally {