在 Blazor 错误边界中获取当前异常

5
我在我的应用程序的某个上下文中生成了一个异常。 我想能够收集它,将其发送到记录器并恢复先前的状态。 Scenario 问题是,由于其当前异常属性受保护,因此无法访问此错误绑定的异常。 enter image description here 解决方案是什么?
3个回答

5
CurrentException属性是受保护的,而不是私有的,因此您可以定义这个类:
public class MyErrorBoundary : ErrorBoundary
{
    public new Exception? CurrentException => base.CurrentException;
}

然后在你的所有代码中将ErrorBoundary替换为MyErrorBoundary。就这么简单。

编辑:以下是我在文件ContainerWithExceptionHandling.razor中如何使用MyErrorBoundary的示例:
@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> Attributes { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    private MyErrorBoundary boundary;
}

<div @attributes="Attributes">
    <ExceptionBoundary @ref="boundary">
        <ChildContent>
            @ChildContent
        </ChildContent>
        <ErrorContent>
            <ExceptionView Exception="@boundary.CurrentException"
                HowToResume="(() => boundary.Recover())" />
        </ErrorContent>
    </ExceptionBoundary>
</div>

在这个例子中,ExceptionView是一个自定义组件,它在一个带有“继续”按钮的框中显示异常的信息。
我的MainLayout.razor文件中有:
<ContainerWithExceptionHandling class="content px-4">
    @Body
</ContainerWithExceptionHandling>

这样一来,如果网页的一个组件在渲染时出现错误信息,那么页面的主要部分将被易于阅读的错误消息所替代,并且恢复正常操作相对较容易。

我该如何在错误页面中使用异常? - Philippe
1
我得出了同样的结论,而且我很惊讶它居然起作用了。为什么微软一开始要限制对异常的访问呢? - Alex
1
我得出了同样的结论,而且我很惊讶它居然起作用了。为什么微软一开始要限制对异常的访问呢? - undefined
1
@奥利迈塔 这看起来是一个非常棒的解决方案,但你如何使用它呢?假设我想在异常发生时显示某种消息。我看不到在使用这个组件的标记中如何获取 CurrentException 。或者我对这个问题有误解吗? - Avrohom Yisroel
@AvrohomYisroel 你可以通过使用@ref来获取CurrentException,从而获取到MyErrorBoundary组件。我已经编辑了我的原始答案,为你说明了这一点。 - Aulimaitar
@AvrohomYisroel 你可以通过使用@ref来获取CurrentException,以获取MyErrorBoundary组件的引用。我已经编辑了我的原始答案,为你说明了这一点。 - undefined

5
我遇到了同样的问题,经过查看源代码后,很容易从ErrorBoundary的ErrorContent中获取当前的异常。
<ErrorBoundary>
                    <ChildContent>
                        @Body
                    </ChildContent>
                    <ErrorContent Context="Exception">
                        <div>
                             @Exception.Message<br/>
                        </div>
                    </ErrorContent>
                </ErrorBoundary>

从错误内容的上下文(RenderFragment)中获取当前异常(请参见上面的代码示例)。

ErrorBoundaryBase ->

/// <summary>
    /// The content to be displayed when there is an error.
    /// </summary>
    [Parameter] public RenderFragment<Exception>? ErrorContent { get; set; }

1
接受答案中的自定义类是可以的,但这是最简单的解决方案。谢谢。 - undefined
这对我来说是有效的,除了@Exception.InnerException没有任何东西...没有堆栈跟踪数据。如果我在我的服务中抛出异常,我只能得到异常消息文本,没有任何指示异常发生在哪个方法/行。 - undefined

1
我希望能够收集它并将其发送到记录器,并恢复先前的状态。
请按照以下方式创建一个组件(Error.razor):
@using Microsoft.Extensions.Logging
@inject ILogger<Error> Logger
@inject IJSRuntime jsRuntime

<CascadingValue Value="this">
@ChildContent
</CascadingValue>    
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }

public void ProcessError(Exception ex)
{
    Logger.LogError("Error:ProcessError - Type: {Type} Message: {Message}",
        ex.GetType(), ex.Message);
    jsRuntime.ToastrError("An Error has occured!"); 
    //StateHasChanged();       
}

}

“Error” 组件可以使用 Blazor 内置的日志记录器记录错误,并通过 “Toastr” 显示 JavaScript 错误消息,方法是通过 “ProcessError” 方法。显然,其他日志记录器,如 Serilog、Elmah 甚至其他自定义日志记录器都可以在此方法中使用。
当错误处理方法想要直接干预组件用户界面的呈现时,将使用 “StateHasChanged”。例如,当我们想要在出现错误后更改页面呈现元素时(更改按钮的颜色或标签或文本框的字体颜色等)。
现在,我们将编辑 “App.razor” 组件如下:
<Error>
    <Router ...>
        ...
    </Router>
</Error>

实际上,我们通过自己的自定义组件(Error.razor)将Router组件封装起来,以便错误组件被级联到将Error视为[CascadingParameter]的任何程序组件中。
现在,在其他组件中处理错误只需要按照以下方式进行即可:
@code {
    [CascadingParameter]
    public Error? Error { get; set; }

    private void CreatePost()
    {
        try
        {
           throw new InvalidOperationException("a message!");
        }
        catch (Exception ex)
        {
            Error?.ProcessError(ex);
        }
    }
}

如您所见,错误组件被定义为一个 CascadingParameter,并且在 try catch 块中调用了 Error 组件的 ProcessError 方法,并将发生的异常发送给它。在我的示例中,Error 组件只有一个错误处理方法。显然,该组件可以具有多个其他自定义错误处理方法,以用于不同的目的。
要将日志保存到服务器上的文本文件中,可以使用 Serilog,其方法在 这里 中有解释。您也可以使用 自定义日志提供程序 将日志保存到数据库中。

这种方法的问题在于它需要显式地处理错误,而ErrorBoundary会自动捕获未处理的异常。我是否忽略了这种方法的任何优势? - Alex
这种方法的问题在于它需要显式的错误处理,而ErrorBoundary会自动捕获未处理的异常。我是否忽略了这种方法的任何优势? - undefined
这种方法的优点是可以将异常记录在某个地方(数据库或文本文件)。 - Arani
这种方法的优势在于可以将异常记录在某个地方(数据库或文本文件)中。 - undefined
使用ErrorBoundary.OnErrorAsync也可以实现相同的功能。 - Alex
使用ErrorBoundary.OnErrorAsync也可以实现相同的效果。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接