如何在Blazor Server中全局捕获并记录控制器异常?
Blazor WASM Core托管应用全局异常捕获方案
后端(ASP.NET Core)全局异常处理中间件
无需在每个控制器方法中添加try-catch,通过全局中间件即可捕获所有请求的未处理异常,并提取控制器、代码行等详细信息:
- 创建异常处理中间件类
public class GlobalExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILogger<GlobalExceptionMiddleware> _logger; private readonly IWebHostEnvironment _env; public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger, IWebHostEnvironment env) { _next = next; _logger = logger; _env = env; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { _logger.LogError(ex, "未处理异常触发"); await HandleExceptionAsync(context, ex); } } private async Task HandleExceptionAsync(HttpContext context, Exception ex) { context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; var errorResponse = new { StatusCode = context.Response.StatusCode, Message = _env.IsDevelopment() ? ex.Message : "服务器内部错误", DetailedInfo = _env.IsDevelopment() ? ex.ToString() : null, ControllerName = context.GetRouteValue("controller")?.ToString(), ActionName = context.GetRouteValue("action")?.ToString() }; await context.Response.WriteAsJsonAsync(errorResponse); } }
- 在Program.cs中注册中间件
注意中间件顺序,需放在UseRouting之后、UseAuthorization之前:
var builder = WebApplication.CreateBuilder(args); // 注册其他服务... var app = builder.Build(); // 配置其他中间件... app.UseMiddleware<GlobalExceptionMiddleware>(); app.UseRouting(); app.UseAuthorization(); app.MapControllers(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.Run();
前端(Blazor WASM)接收并处理后端异常
前端调用API时,统一处理后端返回的自定义错误信息,再传递给ErrorBoundary处理:
- 封装HttpClient统一处理错误
public class ApiService { private readonly HttpClient _httpClient; public ApiService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<T> GetAsync<T>(string url) { var response = await _httpClient.GetAsync(url); if (!response.IsSuccessStatusCode) { var error = await response.Content.ReadFromJsonAsync<ErrorResponse>(); throw new Exception(error?.DetailedInfo ?? error?.Message ?? "请求失败"); } return await response.Content.ReadFromJsonAsync<T>(); } // 同理封装PostAsync、PutAsync等方法 } public class ErrorResponse { public int StatusCode { get; set; } public string Message { get; set; } public string DetailedInfo { get; set; } public string ControllerName { get; set; } public string ActionName { get; set; } }
- 在ErrorBoundary中展示详细异常信息
修改ErrorBoundary的错误内容模板,展示后端返回的完整异常信息:
<ErrorBoundary> <ChildContent> @Body </ChildContent> <ErrorContent Context="exception"> <div class="alert alert-danger"> <h3>错误提示</h3> <p>@exception.Message</p> @if (!string.IsNullOrEmpty(exception.ToString())) { <details> <summary>查看详细信息</summary> <pre>@exception.ToString()</pre> </details> } @SaveLogs(exception) </div> </ErrorContent> </ErrorBoundary>
核心说明
- 开发环境返回完整异常栈、控制器及代码行信息,生产环境自动隐藏敏感细节,避免代码泄露
- 中间件覆盖所有控制器请求的未处理异常,无需在单个Action中编写try-catch
- 前端通过封装HttpClient,将后端错误信息包装为Exception,让ErrorBoundary可以直接捕获并处理
内容的提问来源于stack exchange,提问作者Mahatma Gandhi
相关产品推荐
相关产品推荐

