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

如何在ASP.NET Core API中全局处理值类型可空与空引用异常

ASP.NET Core API 两类参数崩溃问题解决方案

1. 值类型参数接收null导致崩溃问题

把所有值类型批量改成可空值类型不是合理方案,工作量大且会引入大量无意义的空判断逻辑,属于典型的过度改造,优先用以下零/低侵入方案解决:

根源全局处理(零模型代码修改,推荐)

崩溃本质是默认JSON反序列化逻辑不允许给非空值类型赋值null,直接在Program.cs中配置全局JSON序列化规则即可,无需改动任何业务模型代码:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 注册自定义null转默认值转换器,从反序列化层拦截null赋值
        options.JsonSerializerOptions.Converters.Add(new NullToDefaultValueConverter());
    });

配套的通用JSON转换器代码如下:

public class NullToDefaultValueConverter : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        // 仅匹配int/long/double/decimal等非可空值类型
        return typeToConvert.IsValueType && Nullable.GetUnderlyingType(typeToConvert) == null;
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        return (JsonConverter)Activator.CreateInstance(
            typeof(InnerNullDefaultConverter<>).MakeGenericType(typeToConvert))!;
    }

    private class InnerNullDefaultConverter<T> : JsonConverter<T> where T : struct
    {
        public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            // 遇到null直接返回值类型默认值(0/0.0/false等),不抛出反序列化异常
            if (reader.TokenType == JsonTokenType.Null) return default;
            return JsonSerializer.Deserialize<T>(ref reader, options);
        }

        public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
        {
            JsonSerializer.Serialize(writer, value, options);
        }
    }
}

如果不想给null自动赋默认值,而是直接返回参数校验错误,你提到的自定义特性方案完全可行,注意你示例里的特性名存在拼写错误(CheckIIntllegaType应为CheckIllegalType),参考实现如下:

// 自定义校验特性
public class CheckIllegalTypeAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value == null)
        {
            ErrorMessage = "当前参数不允许传递null值";
            return false;
        }
        return true;
    }
}

// 使用方式,直接打在对应属性上即可
public class TestModel
{
    [CheckIllegalType]
    public int testId { get; set; }
}

该方案需要给对应属性加标注,工作量比全局JSON配置大,仅适合需要精细化控制参数校验规则的场景。如果项目用Newtonsoft.Json做序列化,逻辑完全一致,只要把转换器注册到Newtonsoft的序列化选项中即可。

2. 嵌套模型空引用崩溃问题

无需逐一给所有嵌套访问加?.判空,用以下两种通用方案即可解决:

全局异常兜底(零业务代码修改,推荐)

在请求管道最前端加全局异常捕获中间件,统一拦截所有空引用异常,返回标准化错误响应,避免接口直接抛出500错误:

// 注意要放在所有中间件的最前面,保证能捕获所有管道内的异常
app.Use(async (context, next) =>
{
    try
    {
        await next();
    }
    catch (NullReferenceException)
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        await context.Response.WriteAsJsonAsync(new
        {
            Code = 400,
            Msg = "请求参数不合法,存在缺失的嵌套对象字段"
        });
    }
});

编译期空检查(长期维护推荐)

在项目csproj文件中开启C#可空引用类型上下文,编译阶段会自动识别所有未做判空的引用类型访问,插入隐式空检查逻辑,从根源避免空引用崩溃:

<PropertyGroup>
  <Nullable>enable</Nullable>
</PropertyGroup>

开启后所有未标注?的引用类型(包括嵌套子模型),编译器会自动做非空校验,子模型为null时会直接抛出可控的参数验证异常,配合全局异常处理即可实现全链路防护。


内容的提问来源于stack exchange,提问作者Abdul Aleem Solutions

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:33:17