Skip to content

feat(ErrorLogger): Enhance the global exception component function #4030

@izanhzh

Description

@izanhzh

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

我在一个项目中参照了ErrorLogger的实现,但是最终效果不太符合我预期,我也看到有人遇到了类似的问题#217
我希望能够增强ErrorLogger的全局异常处理能力:

  1. 能够自动处理类似OnAfterRenderAsync等这种生命周期中触发的异常,这种异常会导致页面重新渲染,重新触发异常,不断循环
  2. 能够自动处理弹窗内的错误,弹窗出现错误也会导致不断循环

Describe the solution you'd like

经过一番折腾,我能够明白这是Blazor自身全局处理不够强导致,ErrorBoundary 基本不可能做到这种支持,最终我选择了一个妥协一点的方案:

  1. 检测是否触发循环错误渲染,如果是则采用默认的方案,进入错误页面,打断循环,OnAfterRenderAsync这些生命周期中,应当尽量避免异常,或者手动处理异常,但是如果我们想要全局日志记录等,还是需要封装组件统一处理的支持
  2. 检测错误弹窗是否正确渲染出来

以下是我折腾出的代码:

 public class ExceptionHandler : ErrorBoundaryBase
 {
     [Inject]
     private IErrorBoundaryLogger? ErrorBoundaryLogger { get; set; }

     private bool firstRender = true;
     private bool showExceptionMessagePopover = false;
     private int errorRenderCount = 0;

     protected override async Task OnErrorAsync(Exception exception)
     {
         showExceptionMessagePopover = true;
         errorRenderCount++;
         await ErrorBoundaryLogger!.LogErrorAsync(exception);
     }

     protected override void OnAfterRender(bool firstRender)
     {
         this.firstRender = firstRender;
     }

     protected override void BuildRenderTree(RenderTreeBuilder builder)
     {
         int sequence = 0;
         if (CurrentException is null)
         {
             builder.AddContent(sequence++, ChildContent);
         }
         else if (ErrorContent is not null)
         {
             builder.AddContent(sequence++, ErrorContent(CurrentException));
         }
         else
         {
             if (firstRender || errorRenderCount> 2)
             {
                 builder.OpenElement(sequence++, "div");
                 builder.AddAttribute(sequence++, "class", "blazor-error-boundary");
                 builder.CloseElement();
             }
             else
             {
                 builder.AddContent(sequence++, ChildContent);
                 builder.OpenComponent<ExceptionMessagePopover>(3);
                 builder.AddComponentParameter(sequence++, "Open", showExceptionMessagePopover);
                 builder.AddComponentParameter(sequence++, "OpenChanged", EventCallback.Factory.Create<bool>(this, SetShowExceptionMessagePopover));
                 builder.AddComponentParameter(sequence++, "Exception", CurrentException);
                 builder.CloseComponent();
             }
         }
     }
     private void SetShowExceptionMessagePopover(bool value)
     {
         if (showExceptionMessagePopover && !value)//满足此条件,说明错误提示框成功渲染出来了,没有再触发其他异常,这里重置掉相关状态
         {
             errorRenderCount= 0;
             Recover();
         }
         showExceptionMessagePopover = value;
     }
 }

Additional context

No response

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions