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

GraphQL Newtonsoft序列化解析枚举时抛出错误求助

解决方案

问题出在后端返回的蛇形命名枚举值(如SECOND_ITEM)无法被默认序列化器映射到第三方库的帕斯卡命名枚举(如SecondItem),且你的自定义转换器可能存在逻辑缺陷或未正确覆盖默认行为。

核心问题分析

默认的StringEnumConverter不会自动将蛇形命名转换为帕斯卡命名,且如果你的自定义转换器未优先于默认转换器执行,会被默认逻辑覆盖,导致解析失败。

正确实现步骤

1. 编写自定义枚举转换器

实现一个能将蛇形命名字符串转换为帕斯卡命名枚举的转换器,同时支持可空枚举:

public class SnakeCaseToPascalEnumConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        Type enumType = Nullable.GetUnderlyingType(objectType) ?? objectType;
        return enumType.IsEnum;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null && Nullable.GetUnderlyingType(objectType) != null)
        {
            return null;
        }

        if (reader.TokenType != JsonToken.String)
        {
            throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing enum.");
        }

        string snakeCaseValue = reader.Value.ToString();
        Type enumType = Nullable.GetUnderlyingType(objectType) ?? objectType;

        // 将蛇形命名转为帕斯卡命名:SECOND_ITEM → SecondItem
        string pascalCaseName = string.Concat(
            snakeCaseValue.Split('_')
                .Select(part => part.Length > 0 ? char.ToUpper(part[0]) + part.Substring(1).ToLower() : string.Empty)
        );

        // 尝试严格匹配解析
        if (Enum.TryParse(enumType, pascalCaseName, out var result))
        {
            return result;
        }

        // fallback到忽略大小写解析(可选)
        if (Enum.TryParse(enumType, pascalCaseName, ignoreCase: true, out result))
        {
            return result;
        }

        throw new JsonSerializationException($"无法将值 '{snakeCaseValue}' 转换为枚举类型 '{enumType.Name}'.");
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteNull();
            return;
        }

        Type enumType = value.GetType();
        string enumName = Enum.GetName(enumType, value);
        // 将帕斯卡命名转为蛇形(如果需要客户端序列化枚举时也用蛇形格式)
        string snakeCaseName = string.Concat(
            enumName.Select((c, i) => i > 0 && char.IsUpper(c) ? "_" + char.ToUpper(c) : char.ToUpper(c).ToString())
        );

        writer.WriteValue(snakeCaseName);
    }
}

2. 正确配置GraphQL客户端

配置时必须移除默认的StringEnumConverter,避免其优先执行,然后添加自定义转换器:

_graphqlClient = new GraphQLHttpClient(_configuration.GetValue<string>("SomeKey"), new NewtonsoftJsonSerializer(options =>
{
    // 移除默认的StringEnumConverter,避免冲突
    var defaultEnumConverter = options.Converters.OfType<StringEnumConverter>().FirstOrDefault();
    if (defaultEnumConverter != null)
    {
        options.Converters.Remove(defaultEnumConverter);
    }
    // 添加自定义转换器
    options.Converters.Add(new SnakeCaseToPascalEnumConverter());
}));

3. 额外检查项

  • 确保GraphQL.Client.NewtonsoftJson包与Newtonsoft.Json版本兼容,避免版本冲突导致配置不生效
  • 确认后端返回的枚举值格式确实为蛇形大写(如SECOND_ITEM),无拼写错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:02:19