Skip to content

Commit d1a0423

Browse files
committed
Merge branch 'main' into fix-context
2 parents c5fcb4f + f6db501 commit d1a0423

7 files changed

Lines changed: 305 additions & 64 deletions

File tree

src/BootstrapBlazor/Components/ErrorLogger/BootstrapBlazorErrorBoundary.cs

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class BootstrapBlazorErrorBoundary : ErrorBoundaryBase
5656
[NotNull]
5757
public string? ToastTitle { get; set; }
5858

59+
[CascadingParameter, NotNull]
60+
private IErrorLogger? ErrorLogger { get; set; }
61+
5962
/// <summary>
6063
/// <inheritdoc/>
6164
/// </summary>
@@ -76,29 +79,46 @@ protected override Task OnErrorAsync(Exception exception)
7679
protected override void BuildRenderTree(RenderTreeBuilder builder)
7780
{
7881
// 页面生命周期内异常直接调用这里
82+
var pageException = false;
7983
var ex = CurrentException ?? _exception;
8084
if (ex != null)
8185
{
82-
// 处理自定义异常逻辑
83-
if (OnErrorHandleAsync != null)
84-
{
85-
_ = OnErrorHandleAsync(Logger, ex);
86-
return;
87-
}
88-
89-
// 渲染异常内容
90-
builder.AddContent(0, ExceptionContent(ex));
86+
pageException = IsPageException(ex);
9187

9288
// 重置 CurrentException
9389
ResetException();
90+
91+
// 渲染异常
92+
var handler = GetLastOrDefaultHandler();
93+
_ = RenderException(ex, handler);
9494
}
95-
else
95+
96+
// 判断是否为组件周期内异常
97+
if (!pageException)
9698
{
9799
// 渲染正常内容
98100
builder.AddContent(1, ChildContent);
99101
}
100102
}
101103

104+
private static readonly string[] PageMethods = new string[] { "SetParametersAsync", "RunInitAndSetParametersAsync", "OnAfterRenderAsync" };
105+
106+
private static bool IsPageException(Exception ex)
107+
{
108+
var errorMessage = ex.ToString();
109+
return PageMethods.Any(i => errorMessage.Contains(i, StringComparison.OrdinalIgnoreCase));
110+
}
111+
112+
private IHandlerException? GetLastOrDefaultHandler()
113+
{
114+
IHandlerException? handler = null;
115+
if (ErrorLogger is Components.ErrorLogger logger)
116+
{
117+
handler = logger.GetLastOrDefaultHandler();
118+
}
119+
return handler;
120+
}
121+
102122
private PropertyInfo? _currentExceptionPropertyInfo;
103123

104124
private void ResetException()
@@ -119,10 +139,9 @@ private void ResetException()
119139
}
120140
else
121141
{
122-
var index = 0;
123-
builder.OpenElement(index++, "div");
124-
builder.AddAttribute(index++, "class", "error-stack");
125-
builder.AddContent(index++, GetErrorContentMarkupString(ex));
142+
builder.OpenElement(0, "div");
143+
builder.AddAttribute(1, "class", "error-stack");
144+
builder.AddContent(2, GetErrorContentMarkupString(ex));
126145
builder.CloseElement();
127146
}
128147
};
@@ -144,34 +163,40 @@ private MarkupString GetErrorContentMarkupString(Exception ex)
144163
/// <param name="handler"></param>
145164
public async Task RenderException(Exception exception, IHandlerException? handler)
146165
{
166+
// 记录日志
167+
await OnErrorAsync(exception);
168+
147169
// 外部调用
148170
if (OnErrorHandleAsync != null)
149171
{
150172
await OnErrorHandleAsync(Logger, exception);
151-
return;
152173
}
153174

154-
// 记录日志
155-
await OnErrorAsync(exception);
156-
157175
if (handler != null)
158176
{
159-
// 非开发模式下弹窗提示错误信息
160-
await ToastService.Error(ToastTitle, exception.Message);
161-
return;
177+
// IHandlerException 处理异常逻辑
178+
await handler.HandlerExceptionAsync(exception, ExceptionContent);
179+
}
180+
else
181+
{
182+
// 显示异常信息
183+
await ShowErrorToast(exception);
162184
}
163-
164-
// 显示异常信息
165-
await ShowErrorToast(exception);
166-
_exception = exception;
167-
StateHasChanged();
168185
}
169186

170187
private async Task ShowErrorToast(Exception exception)
171188
{
172189
if (ShowToast)
173190
{
174-
await ToastService.Error(ToastTitle, exception.Message);
191+
var option = new ToastOption()
192+
{
193+
Category = ToastCategory.Error,
194+
Title = ToastTitle,
195+
ChildContent = ErrorContent == null
196+
? ExceptionContent(exception)
197+
: ErrorContent(exception)
198+
};
199+
await ToastService.Show(option);
175200
}
176201
}
177202
}

src/BootstrapBlazor/Components/ErrorLogger/ErrorLogger.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,12 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
133133
/// </summary>
134134
/// <param name="exception"></param>
135135
/// <returns></returns>
136-
public Task HandlerExceptionAsync(Exception exception) => _errorBoundary.RenderException(exception, _cache.LastOrDefault());
136+
public Task HandlerExceptionAsync(Exception exception) => _errorBoundary.RenderException(exception, GetLastOrDefaultHandler());
137137

138138
private readonly List<IHandlerException> _cache = [];
139139

140+
internal IHandlerException? GetLastOrDefaultHandler() => _cache.LastOrDefault();
141+
140142
/// <summary>
141143
/// <inheritdoc/>
142144
/// </summary>

src/BootstrapBlazor/Components/Layout/Layout.razor

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@
149149
RefreshToolbarTooltipText="@RefreshToolbarTooltipText" FullscreenToolbarTooltipText="@FullscreenToolbarTooltipText"
150150
OnToolbarRefreshCallback="OnToolbarRefreshCallback" TabHeader="TabHeader" OnCloseTabItemAsync="OnCloseTabItemAsync"
151151
Body="@Main" NotAuthorized="NotAuthorized!" NotFound="NotFound!" NotFoundTabText="@NotFoundTabText"
152-
EnableErrorLogger="@EnableLogger" ErrorLoggerToastTitle="@ErrorLoggerToastTitle">
152+
EnableErrorLogger="@EnableLogger" EnableErrorLoggerILogger="@EnableErrorLoggerILogger"
153+
ShowErrorLoggerToast="ShowErrorLoggerToast" ErrorLoggerToastTitle="@ErrorLoggerToastTitle"
154+
OnErrorHandleAsync="OnErrorHandleAsync">
153155
</Tab>;
154156

155157
RenderFragment RenderFooter =>

src/BootstrapBlazor/Components/Tab/Tab.razor.cs

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

66
using Microsoft.AspNetCore.Components.Web;
77
using Microsoft.Extensions.Localization;
8+
using Microsoft.Extensions.Logging;
89
using System.Collections.Concurrent;
910
using System.Reflection;
1011

@@ -442,12 +443,30 @@ public partial class Tab
442443
[Parameter]
443444
public bool? EnableErrorLogger { get; set; }
444445

446+
/// <summary>
447+
/// 获得/设置 是否记录异常到 <see cref="ILogger"/> 默认 null 使用 <see cref="BootstrapBlazorOptions.EnableErrorLoggerILogger"/> 设置值
448+
/// </summary>
449+
[Parameter]
450+
public bool? EnableErrorLoggerILogger { get; set; }
451+
452+
/// <summary>
453+
/// 获得/设置 是否显示 Error 提示弹窗 默认 null 使用 <see cref="BootstrapBlazorOptions.ShowErrorLoggerToast"/> 设置值
454+
/// </summary>
455+
[Parameter]
456+
public bool? ShowErrorLoggerToast { get; set; }
457+
445458
/// <summary>
446459
/// 获得/设置 错误日志 <see cref="Toast"/> 弹窗标题 默认 null
447460
/// </summary>
448461
[Parameter]
449462
public string? ErrorLoggerToastTitle { get; set; }
450463

464+
/// <summary>
465+
/// 获得/设置 自定义错误处理回调方法
466+
/// </summary>
467+
[Parameter]
468+
public Func<ILogger, Exception, Task>? OnErrorHandleAsync { get; set; }
469+
451470
[CascadingParameter]
452471
private Layout? Layout { get; set; }
453472

src/BootstrapBlazor/Components/Tab/TabItemContent.cs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
55

66
using Microsoft.AspNetCore.Components.Rendering;
7+
using Microsoft.Extensions.Configuration;
78

89
namespace BootstrapBlazor.Components;
910

@@ -15,19 +16,24 @@ class TabItemContent : IComponent, IHandlerException, IDisposable
1516
[Parameter, NotNull]
1617
public TabItem? Item { get; set; }
1718

18-
[CascadingParameter]
19-
private Layout? Layout { get; set; }
20-
2119
[CascadingParameter, NotNull]
2220
private Tab? TabSet { get; set; }
2321

2422
[Inject, NotNull]
2523
private DialogService? DialogService { get; set; }
2624

25+
[Inject]
26+
[NotNull]
27+
private ToastService? ToastService { get; set; }
28+
2729
[Inject]
2830
[NotNull]
2931
private IOptionsMonitor<BootstrapBlazorOptions>? Options { get; set; }
3032

33+
[Inject]
34+
[NotNull]
35+
private IConfiguration? Configuration { get; set; }
36+
3137
private IErrorLogger? _logger;
3238

3339
private RenderHandle _renderHandle;
@@ -52,25 +58,27 @@ private void RenderContent()
5258

5359
private Guid _key = Guid.NewGuid();
5460

61+
private bool EnableErrorLogger => TabSet.EnableErrorLogger ?? Options.CurrentValue.EnableErrorLogger;
62+
private bool EnableErrorLoggerILogger => TabSet.EnableErrorLoggerILogger ?? Options.CurrentValue.EnableErrorLoggerILogger;
63+
private bool ShowErrorLoggerToast => TabSet.ShowErrorLoggerToast ?? Options.CurrentValue.ShowErrorLoggerToast;
64+
private string ToastTitle => TabSet.ErrorLoggerToastTitle ?? "Error";
65+
5566
private void BuildRenderTree(RenderTreeBuilder builder)
5667
{
5768
builder.OpenComponent<ErrorLogger>(0);
5869
builder.SetKey(_key);
5970
builder.AddAttribute(1, nameof(ErrorLogger.ChildContent), Item.ChildContent);
60-
61-
var enableErrorLogger = TabSet.EnableErrorLogger ?? Options.CurrentValue.EnableErrorLogger;
62-
builder.AddAttribute(2, nameof(ErrorLogger.EnableErrorLogger), enableErrorLogger);
63-
64-
// TabItem 不需要 Toast 提示错误信息
65-
builder.AddAttribute(3, nameof(ErrorLogger.ShowToast), false);
66-
builder.AddAttribute(4, nameof(ErrorLogger.ToastTitle), TabSet.ErrorLoggerToastTitle);
67-
builder.AddAttribute(5, nameof(ErrorLogger.OnInitializedCallback), new Func<IErrorLogger, Task>(logger =>
71+
builder.AddAttribute(2, nameof(ErrorLogger.EnableErrorLogger), EnableErrorLogger);
72+
builder.AddAttribute(3, nameof(ErrorLogger.EnableILogger), EnableErrorLoggerILogger);
73+
builder.AddAttribute(4, nameof(ErrorLogger.ShowToast), ShowErrorLoggerToast);
74+
builder.AddAttribute(5, nameof(ErrorLogger.ToastTitle), ToastTitle);
75+
builder.AddAttribute(6, nameof(ErrorLogger.OnInitializedCallback), new Func<IErrorLogger, Task>(logger =>
6876
{
6977
_logger = logger;
7078
_logger.Register(this);
7179
return Task.CompletedTask;
7280
}));
73-
builder.AddAttribute(6, nameof(ErrorLogger.OnErrorHandleAsync), Layout?.OnErrorHandleAsync);
81+
builder.AddAttribute(7, nameof(ErrorLogger.OnErrorHandleAsync), TabSet.OnErrorHandleAsync);
7482
builder.CloseComponent();
7583
}
7684

@@ -83,12 +91,31 @@ public void Render()
8391
RenderContent();
8492
}
8593

94+
private bool _detailedErrorsLoaded;
95+
private bool _showDetailedErrors;
8696
/// <summary>
8797
/// <inheritdoc/>
8898
/// </summary>
8999
/// <param name="ex"></param>
90100
/// <param name="errorContent"></param>
91-
public Task HandlerExceptionAsync(Exception ex, RenderFragment<Exception> errorContent) => DialogService.ShowErrorHandlerDialog(errorContent(ex));
101+
public async Task HandlerExceptionAsync(Exception ex, RenderFragment<Exception> errorContent)
102+
{
103+
if (!_detailedErrorsLoaded)
104+
{
105+
_showDetailedErrors = Configuration.GetValue("DetailedErrors", false);
106+
_detailedErrorsLoaded = true;
107+
}
108+
109+
var useDialog = _showDetailedErrors || !ShowErrorLoggerToast;
110+
if (useDialog)
111+
{
112+
await DialogService.ShowErrorHandlerDialog(errorContent(ex));
113+
}
114+
else
115+
{
116+
await ToastService.Error(ToastTitle, ex.Message);
117+
}
118+
}
92119

93120
/// <summary>
94121
/// IDispose 方法用于释放资源

src/BootstrapBlazor/wwwroot/scss/root.scss

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@use "variables" as *;
1+
@use "variables" as *;
22

33
:root {
44
--bb-primary-color: #{$bb-primary-color};
@@ -82,35 +82,41 @@ a, a:hover, a:focus {
8282
display: none;
8383
}
8484

85-
::view-transition-old(*) {
85+
::view-transition-old(root) {
8686
mix-blend-mode: normal;
8787
animation: none;
8888
z-index: 1;
8989
}
9090

91-
::view-transition-new(*) {
91+
::view-transition-new(root) {
92+
will-change: clip-path, opacity;
9293
mix-blend-mode: normal;
93-
animation: clip .3s ease-in-out;
94+
animation: clip .3s ease-in-out both;
9495
z-index: 9999;
9596
}
9697

9798
@keyframes clip {
9899
from {
99100
clip-path: circle(0% at var(--bb-theme-x) var(--bb-theme-y));
101+
opacity: 0.99;
102+
transform: translateZ(0);
100103
}
101104

102105
to {
103106
clip-path: circle(100% at var(--bb-theme-x) var(--bb-theme-y));
107+
opacity: 1;
108+
transform: translateZ(0);
104109
}
105110
}
106111

107112
[data-bs-theme='dark'] {
108-
&::view-transition-old(*) {
109-
animation: clip2 .3s ease-in-out;
113+
&::view-transition-old(root) {
114+
will-change: clip-path, opacity;
115+
animation: clip2 .3s ease-in-out both;
110116
z-index: 9999;
111117
}
112118

113-
&::view-transition-new(*) {
119+
&::view-transition-new(root) {
114120
animation: none;
115121
z-index: 1;
116122
}
@@ -119,10 +125,14 @@ a, a:hover, a:focus {
119125
@keyframes clip2 {
120126
from {
121127
clip-path: circle(100% at var(--bb-theme-x) var(--bb-theme-y));
128+
opacity: 0.99;
129+
transform: translateZ(0);
122130
}
123131

124132
to {
125133
clip-path: circle(0% at var(--bb-theme-x) var(--bb-theme-y));
134+
opacity: 1;
135+
transform: translateZ(0);
126136
}
127137
}
128138

0 commit comments

Comments
 (0)