You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET 6 WebAPI自定义JsonConverter转Password对象抛异常问题

问题解答

以下是对应问题的明确结论和可直接落地的实现方案:

  • 合法性校验的正确实现方式

    首先要划清职责边界:

    1. JsonConverter的Read方法只负责格式层面的转换校验:先判断当前JSON Token类型是不是字符串,再调用Password.TryParse完成字符串到Password实例的转换。不要把依赖数据库、其他服务的业务校验(比如密码是否和历史重复、是否匹配账号对应规则)塞到Converter里,这类业务校验要放到Controller模型绑定完成后的阶段,用数据注解或者校验库实现即可。
    2. 你现在抛异常导致应用中断,根本不是校验逻辑本身的问题,是Program.cs里中间件顺序错误,或者接收参数的Controller没加[ApiController]特性。.NET 6 WebAPI只要管线配置正确,反序列化阶段抛出的合规异常会被自动捕获,不会导致进程终止。
    3. 读取JSON值的时候必须先判断Token类型,否则传入非字符串值(比如数字、嵌套对象)时,直接调用reader.GetString()会抛出不受框架识别的底层异常。
  • 校验失败的异常类型选择

    校验失败必须抛内置的System.Text.Json.JsonException,这是唯一被System.Text.Json序列化管线、ASP.NET Core模型绑定机制识别的请求错误类型,会被自动包装为400 Bad Request响应返回给客户端。
    不要抛自定义异常、ArgumentException、ValidationException这类异常,这些会被框架判定为服务端内部错误,返回500状态码,未被全局异常处理捕获时就会出现你遇到的进程中断问题。
    抛JsonException的时候建议带上当前JSON路径,方便前端快速定位错误字段:

    throw new JsonException("密码格式不合法,需满足8-16位,包含大小写字母与数字", reader.Path, null);
    
  • 不要在CanConvert方法里做值校验

    完全不可行,原因有两个:

    1. CanConvert方法的入参只有待转换的CLR类型,没有传入Utf8JsonReader实例,方法执行时JSON payload还没开始读取,你根本拿不到请求传递的密码字符串,没有做值校验的基础。
    2. CanConvert的执行结果会被序列化框架缓存,在应用启动阶段、序列化流程初始化时会被多次调用,在这里塞业务逻辑会严重拉低性能,甚至导致序列化缓存逻辑错乱。

修正后的完整实现代码

自定义JsonConverter代码

namespace TestApp.Converters
{
    public class PasswordJsonConverter : JsonConverter<Password>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert == typeof(Password);
        }

        public override Password? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            // 先校验Token类型,避免非字符串值触发底层非预期异常
            if (reader.TokenType != JsonTokenType.String)
            {
                throw new JsonException("密码字段必须是字符串类型", reader.Path, null);
            }

            string? input = reader.GetString();
            if(!Password.TryParse(input, out Password pw))
            {
                throw new JsonException("密码格式不符合要求,长度需为8-16位,同时包含大小写字母、数字", reader.Path, null);
            }

            return pw;
        }

        public override void Write(Utf8JsonWriter writer, Password value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
}

Program.cs 管线正确配置(注意中间件顺序)

var builder = WebApplication.CreateBuilder(args);

// 注册控制器服务,注入自定义JsonConverter
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new PasswordJsonConverter());
    });

var app = builder.Build();

// 异常处理中间件必须放在所有其他业务中间件的最前面
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

注意:所有接收Password类型参数的Controller必须标注[ApiController]特性,该特性自带的模型验证过滤器会自动捕获反序列化阶段的JsonException,统一返回结构化的400错误响应,不会让异常冒泡导致应用中断。


内容的提问来源于stack exchange,提问作者user9573909

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 14:21:12