请求参数中字符串转枚举类型失败的问题

132 阅读2分钟

请求参数中字符串转枚举类型失败的问题

在 ASP.NET 8 中的 API 参数中,定义一个枚举参数,从前端传过来的是枚举值字符串,无法自动转化成字符串的问题。并且报错了。我发现在 ASP.NET 5中就没有这个问题,ASP.NET 8 中存在这种问题,具体报错内容如下:

{
	"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
	"title": "One or more validation errors occurred.",
	"status": 400,
	"errors": {
		"param": [
			"The param field is required."
		],
		"$.dataScope": [
			"The JSON value could not be converted to BY.FusionHub.Common.Enums.DataScopeEnum. Path: $.dataScope | LineNumber: 2 | BytePositionInLine: 20."
		]
	},
	"traceId": "00-1f7814d90e35e0d45e9341f0dd268fb6-9bdb4c3dd7687e02-00"
}

枚举类型:

public enum DataScopeEnum
{
    ALL = 0,
    CUSTOM = 1,
    DEPT = 2,
    DEPT_FOLLOW = 3,
    USER = 4,
}

API:

[HttpPut("DataScope/{id:int}")]
public async Task<ApiResult> UpdateSystemRole(int id, RolePermissionModel param)
{
    return await _systemRoleService.UpdateSystemRolePermission(id, param);
}

Model:

public class RolePermissionModel : BaseModel
{
    /// <summary>
    /// 数据范围(0:全部数据权限 1:自定数据权限 2:本部门数据权限 3:本部门及以下数据权限 4:仅个人数据权限)
    /// </summary>
    public DataScopeEnum DataScope { get; set; }

    /// <summary>
    /// 部门树选择项是否关联显示
    /// </summary>
    public bool DepartmentCheckStrictly { get; set; } = false;

    /// <summary>
    /// 部门ID数组
    /// </summary>
    public int[]? DepartmentList { get; set; }
}

原因

因为在 ASP.NET Core 6.0 以后,默认的 JSON 序列化行为发生了一些变化。ASP.NET Core 8.0 默认使用的是 System.Text.Json 作为 JSON 序列化/反序列化的库,而在 ASP.NET Core 5.0 时,默认使用的是 Newtonsoft.Json(如果没有显式更改的话)。

System.Text.Json 的枚举序列化行为比 Newtonsoft.Json 更严格。默认情况下,System.Text.Json 会要求枚举值的字符串完全匹配枚举名称(包括大小写)。而在 Newtonsoft.Json 中,它会在某些情况下进行更宽松的匹配(例如,忽略大小写)。

解决办法

方法一

System.Text.Json 中,你可以通过设置 JsonSerializerOptions 来启用枚举的大小写不敏感的转换。

修改 Program.csStartup.cs 中的 AddJsonOptions 配置,启用大小写不敏感的枚举转换:

/// <summary>
/// 添加控制器服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddControllersService(this IServiceCollection services)
{
    services.AddControllers()       // 添加控制器
        .AddJsonOptions(options =>  // 配置 JSON 转换器
    {
        // 添加字符串转枚举转换器
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
        // 允许尾随逗号
        options.JsonSerializerOptions.AllowTrailingCommas = true;
    });
    return services;
}

方法二

将 JSON 序列化器更改为 Newtonsoft.Json ,在 Program.cs 中注册 Newtonsoft.Json

services.AddControllers()
        .AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            options.SerializerSettings.Formatting = Formatting.Indented;
        });