Skip to content

Commit 8b47783

Browse files
authored
feat(IErrorLogger): support Release mode only show exception message (#6152)
* chore: 增加 Hosting 依赖 * refactor: 增加开发模式检查 * test: 更新单元测试 * refactor: 重构代码
1 parent 4640cae commit 8b47783

File tree

10 files changed

+113
-49
lines changed

10 files changed

+113
-49
lines changed

src/BootstrapBlazor/Components/ErrorLogger/BootstrapBlazorErrorBoundary.cs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using Microsoft.AspNetCore.Components.Rendering;
77
using Microsoft.Extensions.Configuration;
8+
using Microsoft.Extensions.Hosting;
89
using Microsoft.Extensions.Logging;
910
using System.Reflection;
1011

@@ -31,6 +32,10 @@ class BootstrapBlazorErrorBoundary : ErrorBoundaryBase
3132
[NotNull]
3233
private NavigationManager? NavigationManager { get; set; }
3334

35+
[Inject]
36+
[NotNull]
37+
private IHostEnvironment? HostEnvironment { get; set; }
38+
3439
/// <summary>
3540
/// 获得/设置 自定义错误处理回调方法
3641
/// </summary>
@@ -54,13 +59,10 @@ class BootstrapBlazorErrorBoundary : ErrorBoundaryBase
5459
/// <inheritdoc/>
5560
/// </summary>
5661
/// <param name="exception"></param>
57-
protected override async Task OnErrorAsync(Exception exception)
62+
protected override Task OnErrorAsync(Exception exception)
5863
{
59-
if (ShowToast)
60-
{
61-
await ToastService.Error(ToastTitle, exception.Message);
62-
}
6364
Logger.LogError(exception, "{BootstrapBlazorErrorBoundary} {OnErrorAsync} log this error occurred at {Page}", nameof(BootstrapBlazorErrorBoundary), nameof(OnErrorAsync), NavigationManager.Uri);
65+
return Task.CompletedTask;
6466
}
6567

6668
/// <summary>
@@ -69,13 +71,13 @@ protected override async Task OnErrorAsync(Exception exception)
6971
/// <param name="builder"></param>
7072
protected override void BuildRenderTree(RenderTreeBuilder builder)
7173
{
74+
// 页面生命周期内异常直接调用这里
7275
var ex = CurrentException ?? _exception;
7376
if (ex != null)
7477
{
7578
// 处理自定义异常逻辑
7679
if (OnErrorHandleAsync != null)
7780
{
78-
// 页面生命周期内异常直接调用这里
7981
_ = OnErrorHandleAsync(Logger, ex);
8082
return;
8183
}
@@ -132,7 +134,7 @@ private MarkupString GetErrorContentMarkupString(Exception ex)
132134
}
133135

134136
/// <summary>
135-
/// 渲染异常信息方法
137+
/// BootstrapBlazor 组件导致异常渲染方法
136138
/// </summary>
137139
/// <param name="exception"></param>
138140
/// <param name="handler"></param>
@@ -145,14 +147,35 @@ public async Task RenderException(Exception exception, IHandlerException? handle
145147
return;
146148
}
147149

150+
// 记录日志
151+
await OnErrorAsync(exception);
152+
148153
if (handler != null)
149154
{
150-
await handler.HandlerException(exception, ExceptionContent);
155+
if (HostEnvironment.IsDevelopment())
156+
{
157+
// IHandlerException 处理异常逻辑
158+
await handler.HandlerException(exception, ExceptionContent);
159+
}
160+
else
161+
{
162+
// 非开发模式下弹窗提示错误信息
163+
await ToastService.Error(ToastTitle, exception.Message);
164+
}
151165
return;
152166
}
153167

154-
await OnErrorAsync(exception);
168+
// 显示异常信息
169+
await ShowErrorToast(exception);
155170
_exception = exception;
156171
StateHasChanged();
157172
}
173+
174+
private async Task ShowErrorToast(Exception exception)
175+
{
176+
if (ShowToast)
177+
{
178+
await ToastService.Error(ToastTitle, exception.Message);
179+
}
180+
}
158181
}

src/BootstrapBlazor/Components/Layout/Layout.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ private Task OnErrorLoggerInitialized(ErrorLogger logger)
673673
private RenderFragment? _errorContent;
674674

675675
/// <summary>
676-
/// HandlerException 错误处理方法
676+
/// <inheritdoc/>
677677
/// </summary>
678678
/// <param name="ex"></param>
679679
/// <param name="errorContent"></param>

src/BootstrapBlazor/Components/Modal/ModalDialog.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ private RenderFragment RenderBodyTemplate() => builder =>
449449
protected RenderFragment? _errorContent;
450450

451451
/// <summary>
452-
/// HandlerException 错误处理方法
452+
/// <inheritdoc/>
453453
/// </summary>
454454
/// <param name="ex"></param>
455455
/// <param name="errorContent"></param>

src/BootstrapBlazor/Components/Tab/TabItemContent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public void Render()
9393
}
9494

9595
/// <summary>
96-
/// HandlerException 错误处理方法
96+
/// <inheritdoc/>
9797
/// </summary>
9898
/// <param name="ex"></param>
9999
/// <param name="errorContent"></param>

src/BootstrapBlazor/Directory.Build.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(NET8Version)" />
3535
<PackageReference Include="Microsoft.Extensions.Localization" Version="$(NET6Version)" />
3636
<PackageReference Include="Microsoft.Extensions.Http" Version="$(NET8Version)" />
37+
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET8Version)" />
3738
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(NET8Version)" />
3839
</ItemGroup>
3940

@@ -44,6 +45,7 @@
4445
<PackageReference Include="Microsoft.Extensions.Localization" Version="$(NET7Version)" />
4546
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(NET8Version)" />
4647
<PackageReference Include="Microsoft.Extensions.Http" Version="$(NET8Version)" />
48+
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET8Version)" />
4749
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(NET8Version)" />
4850
</ItemGroup>
4951

@@ -53,6 +55,7 @@
5355
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(NET8Version)" />
5456
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(NET8Version)" />
5557
<PackageReference Include="Microsoft.Extensions.Http" Version="$(NET8Version)" />
58+
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET8Version)" />
5659
<PackageReference Include="Microsoft.Extensions.Localization" Version="$(NET8Version)" />
5760
</ItemGroup>
5861

@@ -62,6 +65,7 @@
6265
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(NET9Version)" />
6366
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(NET9Version)" />
6467
<PackageReference Include="Microsoft.Extensions.Http" Version="$(NET9Version)" />
68+
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET9Version)" />
6569
<PackageReference Include="Microsoft.Extensions.Localization" Version="$(NET9Version)" />
6670
</ItemGroup>
6771

test/UnitTest/Components/BootstrapBlazorRootTest.cs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,19 @@
55

66
//using HarmonyLib;
77

8+
using Bunit.TestDoubles;
9+
810
namespace UnitTest.Components;
911

1012
public class BootstrapBlazorRootTest : TestBase
1113
{
1214
[Fact]
1315
public void Render_Ok()
1416
{
15-
var context = new TestContext();
16-
context.JSInterop.Mode = JSRuntimeMode.Loose;
17-
18-
var sc = context.Services;
19-
sc.AddBootstrapBlazor();
20-
sc.ConfigureJsonLocalizationOptions(op =>
21-
{
22-
op.IgnoreLocalizerMissing = false;
23-
});
24-
sc.AddScoped<IRootComponentGenerator, MockGenerator>();
25-
var cut = context.RenderComponent<BootstrapBlazorRoot>();
17+
Context.Services.AddBootstrapBlazor();
18+
Context.Services.AddScoped<IRootComponentGenerator, MockGenerator>();
19+
Context.Services.GetRequiredService<ICacheManager>();
20+
var cut = Context.RenderComponent<BootstrapBlazorRoot>();
2621
cut.Contains("<div class=\"auto-generator\"></div>");
2722
}
2823

test/UnitTest/Components/ErrorLoggerTest.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
using Microsoft.AspNetCore.Components.Web;
77
using Microsoft.Extensions.Configuration;
8+
using Microsoft.Extensions.FileProviders;
9+
using Microsoft.Extensions.Hosting;
810

911
namespace UnitTest.Components;
1012

@@ -161,7 +163,7 @@ public void ErrorContent_Ok()
161163
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
162164
{
163165
pb.Add(a => a.EnableErrorLogger, true);
164-
pb.Add(a => a.ShowToast, false);
166+
pb.Add(a => a.ShowToast, true);
165167
pb.AddChildContent<Button>(pb =>
166168
{
167169
pb.Add(b => b.OnClick, () =>
@@ -217,6 +219,30 @@ public async Task TabItem_Error()
217219
((IDisposable)content).Dispose();
218220
}
219221

222+
[Fact]
223+
public async Task TabItem_Production_Error()
224+
{
225+
var context = new TestContext();
226+
context.JSInterop.Mode = JSRuntimeMode.Loose;
227+
context.Services.AddSingleton<IHostEnvironment, MockProductionEnironment>();
228+
context.Services.AddBootstrapBlazor();
229+
context.Services.GetRequiredService<ICacheManager>();
230+
231+
var cut = context.RenderComponent<BootstrapBlazorRoot>(pb =>
232+
{
233+
pb.AddChildContent<Tab>(pb =>
234+
{
235+
pb.AddChildContent<TabItem>(pb =>
236+
{
237+
pb.Add(a => a.Text, "Text1");
238+
pb.Add(a => a.ChildContent, builder => builder.AddContent(0, RenderButton()));
239+
});
240+
});
241+
});
242+
var button = cut.Find("button");
243+
await cut.InvokeAsync(() => button.Click());
244+
}
245+
220246
private RenderFragment RenderButton() => builder =>
221247
{
222248
builder.OpenComponent<Button>(0);
@@ -227,4 +253,15 @@ private RenderFragment RenderButton() => builder =>
227253
}));
228254
builder.CloseComponent();
229255
};
256+
257+
class MockProductionEnironment : IHostEnvironment
258+
{
259+
public string EnvironmentName { get; set; } = "Production";
260+
261+
public string ApplicationName { get; set; } = "Test";
262+
263+
public string ContentRootPath { get; set; } = "UniTest";
264+
265+
public IFileProvider ContentRootFileProvider { get; set; } = null!;
266+
}
230267
}

test/UnitTest/Core/TestBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ public TestBase()
1313
{
1414
Context = new TestContext();
1515
Context.JSInterop.Mode = JSRuntimeMode.Loose;
16+
17+
Context.Services.AddMockEnvironment();
1618
}
1719
}

test/UnitTest/Extensions/IServiceCollectionExtensions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
55

66
using Microsoft.Extensions.Configuration;
7+
using Microsoft.Extensions.FileProviders;
8+
using Microsoft.Extensions.Hosting;
79

810
namespace Microsoft.Extensions.DependencyInjection;
911

@@ -24,4 +26,21 @@ public static IServiceCollection AddConfiguration(this IServiceCollection servic
2426
services.AddSingleton<IConfiguration>(config);
2527
return services;
2628
}
29+
30+
public static IServiceCollection AddMockEnvironment(this IServiceCollection services)
31+
{
32+
services.AddSingleton<IHostEnvironment, MockEnvironment>();
33+
return services;
34+
}
35+
36+
class MockEnvironment : IHostEnvironment
37+
{
38+
public string EnvironmentName { get; set; } = "Development";
39+
40+
public string ApplicationName { get; set; } = "Test";
41+
42+
public string ContentRootPath { get; set; } = "UnitTest";
43+
44+
public IFileProvider ContentRootFileProvider { get; set; } = null!;
45+
}
2746
}

test/UnitTest/Services/MaskServiceTest.cs

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,13 @@ namespace UnitTest.Services;
88
/// <summary>
99
/// MaskService 单元测试
1010
/// </summary>
11-
public class MaskServiceTest : TestBase
11+
public class MaskServiceTest : BootstrapBlazorTestBase
1212
{
1313
[Fact]
1414
public async Task Mask_Ok()
1515
{
16-
var context = new TestContext();
17-
context.JSInterop.Mode = JSRuntimeMode.Loose;
18-
context.Services.AddBootstrapBlazor();
19-
20-
var maskService = context.Services.GetRequiredService<MaskService>();
21-
var cut = context.RenderComponent<BootstrapBlazorRoot>(pb =>
16+
var maskService = Context.Services.GetRequiredService<MaskService>();
17+
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
2218
{
2319
pb.AddChildContent<Button>(pb =>
2420
{
@@ -49,12 +45,8 @@ await maskService.Show(new MaskOption()
4945
[Fact]
5046
public async Task Container_Ok()
5147
{
52-
var context = new TestContext();
53-
context.JSInterop.Mode = JSRuntimeMode.Loose;
54-
context.Services.AddBootstrapBlazor();
55-
56-
var maskService = context.Services.GetRequiredService<MaskService>();
57-
var cut = context.RenderComponent<BootstrapBlazorRoot>(pb =>
48+
var maskService = Context.Services.GetRequiredService<MaskService>();
49+
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
5850
{
5951
pb.AddChildContent<Button>(pb =>
6052
{
@@ -87,12 +79,8 @@ await maskService.Show(new MaskOption()
8779
[Fact]
8880
public async Task Show_Component()
8981
{
90-
var context = new TestContext();
91-
context.JSInterop.Mode = JSRuntimeMode.Loose;
92-
context.Services.AddBootstrapBlazor();
93-
94-
var maskService = context.Services.GetRequiredService<MaskService>();
95-
var cut = context.RenderComponent<BootstrapBlazorRoot>(pb =>
82+
var maskService = Context.Services.GetRequiredService<MaskService>();
83+
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
9684
{
9785
pb.AddChildContent<Button>(pb =>
9886
{
@@ -109,12 +97,8 @@ public async Task Show_Component()
10997
[Fact]
11098
public async Task Show_Type()
11199
{
112-
var context = new TestContext();
113-
context.JSInterop.Mode = JSRuntimeMode.Loose;
114-
context.Services.AddBootstrapBlazor();
115-
116-
var maskService = context.Services.GetRequiredService<MaskService>();
117-
var cut = context.RenderComponent<BootstrapBlazorRoot>(pb =>
100+
var maskService = Context.Services.GetRequiredService<MaskService>();
101+
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
118102
{
119103
pb.AddChildContent<Button>(pb =>
120104
{

0 commit comments

Comments
 (0)