.NET7 WebApi JSON反序列化异常消息本地化及处理方案咨询
解决方案
一、捕获反序列化异常并返回固定JSON格式
这类JSON反序列化异常发生在模型绑定之前,ConfigureApiBehaviorOptions无法覆盖这个阶段的错误处理,需要通过自定义异常处理器来捕获并返回固定格式响应。
- 实现
IExceptionHandler接口处理异常:
using Microsoft.AspNetCore.Diagnostics; using System.Text.Json; public class JsonDeserializationExceptionHandler : IExceptionHandler { private readonly ILogger<JsonDeserializationExceptionHandler> _logger; public JsonDeserializationExceptionHandler(ILogger<JsonDeserializationExceptionHandler> logger) { _logger = logger; } public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { // 匹配JSON反序列化相关异常 if (exception is JsonException || exception.Message.Contains("JSON", StringComparison.OrdinalIgnoreCase)) { _logger.LogError(exception, "JSON反序列化失败"); // 构造固定格式响应体 var errorResponse = new { Status = StatusCodes.Status400BadRequest, Code = "INVALID_JSON", Message = "请求体格式错误,请提供有效的JSON内容", Timestamp = DateTime.UtcNow }; httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; httpContext.Response.ContentType = "application/json"; await httpContext.Response.WriteAsync(JsonSerializer.Serialize(errorResponse), cancellationToken); return true; // 标记异常已处理 } return false; // 其他异常交给后续管道处理 } }
- 在
Program.cs中注册并启用异常处理器:
builder.Services.AddExceptionHandler<JsonDeserializationExceptionHandler>(); builder.Services.AddProblemDetails(); // 可选,用于兜底的问题详情处理 // 中间件顺序:放在UseRouting之后,UseEndpoints之前 app.UseExceptionHandler();
二、实现反序列化异常消息本地化
结合IStringLocalizer实现多语言消息替换,步骤如下:
- 创建本地化资源文件
在项目中添加Resources文件夹,创建资源文件(如ErrorMessages.resx、ErrorMessages.zh-CN.resx),添加对应键值对:
BadRequestTitle: 请求格式错误InvalidJsonMsg: 请求体不是有效的JSON格式,请检查后重试EmptyBodyMsg: 请求体内容为空,请提供有效的JSON数据
- 修改异常处理器注入本地化服务:
using Microsoft.AspNetCore.Diagnostics; using Microsoft.Extensions.Localization; using System.Text.Json; public class LocalizedJsonDeserializationHandler : IExceptionHandler { private readonly ILogger<LocalizedJsonDeserializationHandler> _logger; private readonly IStringLocalizer<ErrorMessages> _localizer; public LocalizedJsonDeserializationHandler( ILogger<LocalizedJsonDeserializationHandler> logger, IStringLocalizer<ErrorMessages> localizer) { _logger = logger; _localizer = localizer; } public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { if (exception is JsonException jsonEx) { _logger.LogError(jsonEx, "JSON反序列化失败"); string detailMsg; // 区分空请求体和无效JSON的情况 if (httpContext.Request.ContentLength == 0 || jsonEx.Message.Contains("empty", StringComparison.OrdinalIgnoreCase)) { detailMsg = _localizer["EmptyBodyMsg"]; } else { detailMsg = _localizer["InvalidJsonMsg"]; } var localizedResponse = new { Status = StatusCodes.Status400BadRequest, Title = _localizer["BadRequestTitle"], Detail = detailMsg, Timestamp = DateTime.UtcNow }; httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; httpContext.Response.ContentType = "application/json"; await httpContext.Response.WriteAsync(JsonSerializer.Serialize(localizedResponse), cancellationToken); return true; } return false; } }
- 配置本地化服务和中间件:
// 注册本地化服务 builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); builder.Services.AddControllers() .AddDataAnnotationsLocalization() // 保留已有的DataAnnotations本地化配置 .AddJsonOptions(options => { // 可根据需求配置JSON序列化选项 }); // 注册本地化异常处理器 builder.Services.AddExceptionHandler<LocalizedJsonDeserializationHandler>(); builder.Services.AddProblemDetails(); // 配置请求本地化中间件(需放在UseExceptionHandler之前) var supportedCultures = new[] { "zh-CN", "en-US" }; var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions); app.UseExceptionHandler();
关键说明
ConfigureApiBehaviorOptions仅处理模型绑定完成后的验证错误,无法覆盖反序列化阶段的异常,因此必须通过IExceptionHandler拦截。- 可以通过检查请求体长度或
JsonException的具体消息,精准区分“空请求体”和“无效JSON”两种场景。
内容的提问来源于stack exchange,提问作者Jarvie789
相关产品推荐
相关产品推荐

