深入浅出Blazor webassembly之异常错误显示
Blazor wasm 原生模版中没有提供对End user友好的异常处理机制. 一般情况下我们都需要自行实现一套自己的异常处理机制
==============================
原生的异常处理机制
==============================
Fetch.razor 的初始化代码, 加载一个不存在的json 文件, 导致程序异常, 未做特殊处理的情况.
protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/not_found.json"); }
==============================
简单的JS alert处理机制
==============================
注入 IJSRuntime 调用 js alert 函数来处理异常, 对于End user 稍微好了一些, 但还是不够友好.
[Inject] IJSRuntime Js { get; set; } protected override async Task OnInitializedAsync() { try { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/not_found.json"); } catch (Exception ex) { await Js.InvokeVoidAsync("alert", ex.Message); } }
==============================
自定义全局异常处理机制: Layout中内置一个全局的ErrorComponent
==============================
1. 声明一个 IErrorComponent 接口
namespace WebApplication2 { public interface IErrorComponent { void ShowError(string title, string message); } }
2. MainLayout.razor 实现 IErrorComponent接口, 并提供显示和关闭Error
@inherits LayoutComponentBase @implements IErrorComponent <div class="page"> <div class="sidebar"> <NavMenu /> </div> <div class="main"> <div class="top-row px-4"> <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a> </div> <div class="content px-4"> @if (_IsErrorActive) { <div class="alert alert-danger" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close1" @onclick="HideError"> <span aria-hidden="true">×</span> </button> </div> <h3>@_Title</h3> <p>@_Message</p> } <CascadingValue Value="this" Name="ErrorComponent"> @Body </CascadingValue> </div> </div> </div> @code{ bool _IsErrorActive; String _Title; String _Message; public void ShowError(string title, string message) { this._IsErrorActive = true; this._Title = title; this._Message = message; StateHasChanged(); } private void HideError() { this._IsErrorActive = false; } }
改造之前, content 部分非常简单, 代码见下, 改造之后, 在@Body 加了显示 error message的 alert 卡片.
<div class="content px-4"> @Body </div>
另外, 使用 CascadingValue 组件将 MainLayout 作为 IErrorComponent 的实例传导到各个页面中.
3. FetchData.razor 文件中, 使用 CascadingParameter 承接 IErrorComponent 实例, 并在异常点使用该实例显示出来.
[CascadingParameter(Name = "ErrorComponent")] IErrorComponent _ErrorComponent { get; set; } protected override async Task OnInitializedAsync() { try { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/not_found.json"); } catch (Exception ex) { _ErrorComponent.ShowError(ex.Message, ex.StackTrace); } }
效果图:
==============================
参考
==============================
https://nightbaker.github.io/gitflow/azure/piplines/2020/01/22/blazor-error-component/
https://nightbaker.github.io/blazor/exception/2021/08/11/throws-exceptions-to-blazor/