反序列化 RestClient 响应枚举转换错误 - 无法将 JSON 值转换为枚举

Deserialize RestClient response Enum Conversion Error - The JSON value could not be converted to Enum

提问人:Hakuna Matata 提问时间:8/23/2023 最后编辑:Uwe KeimHakuna Matata 更新时间:9/20/2023 访问量:164

问:

在我们的 asp.net 应用程序中,我们最近从 restsharp 106.12.0 升级到 110.2.0。 旧版本没有问题,但是在升级后对代码进行了很少的更改,我们收到了错误:

无法将 JSON 值转换为 SubExCore.Models.Enums.YearType. 路径:$.body。年份类型 |行号:0 |BytePositionInLine:

无法将 JSON 值转换为 System.Nullable'1[SubExCore.Models.Enums.SectionType]。路径: $.body.sectionType |行号:0 |BytePositionInLine

这是我通过反序列化 json 响应响应来获取 YearBook 响应的 api 方法。

        public YearBook GetYearBook()
        {
            RestRequest request = new RestRequest(MethodType)
            {
                RequestFormat = DataFormat.Json,
                Resource = ApiPath,
                Method = Method.GET,
                JsonSerializer = new CustomJsonSerializer()
            };
            RestRequest request = new RestRequest() { RequestFormat = DataFormat.Json, Resource = ApiPath, Method = Method.Get };
            var options = new RestClientOptions()
            {
                BaseUrl = new Uri(BaseAddress),
                CachePolicy = new System.Net.Http.Headers.CacheControlHeaderValue() { NoCache = true, NoStore = true }
            };
            RestClient client = new RestClient(options);
            if (!Token.IsNullOrWhiteSpace())
            {
                client.AddDefaultHeader("Authorization", "authToken " + Token);
            }
            client.AddDefaultHeader("Cache-Control", "no-cache");
            var myresonse = client.Execute<YearBook>(request);
            return myresonse.Data;
        }

这是我的 YearBook 类,带有 Enum 属性

[Table(TableName = "tblYearBook")]
public class YearBook
{
    [Map(ColumnName = "year_id"), Key]
    public int Year { get; set; }

    [Map(ColumnName = "year_type")]
    public YearType YearType { get; set; }

    [Map(ColumnName = "section_type")]
    public SectionType? Section { get; set; }

    [Map(ColumnName = "college_name")]
    public string CollegeName { get; set; }

    [Map(ColumnName = "avg_pass")]
    public decimal AvgPass { get; set; }
}

public enum YearType
{
    FirstYear,
    SecondYear,
    ThirdYear
}

public enum SectionType
{
     None,
     MIT,
     BIT
}

这是我从该方法获得的 json 响应。

{
    "year_id": "2005",
    "year_type": "FirstYear",
    "section_type": "None",
    "college_name": "St. Alphores Govt College",
    "avg_pass" : 89
}

前面,我们已经在 RestSharp.Serializers.ISerializer 中实现了 CustomSerializer。新的 Restsharp 版本现在实现了 IRestSerializer 中的 customserializer。互联网上的 Restsharp 文档 neight 中没有足够的细节。 谁能给我一个正确的IRestSerializer实现,它具有以下序列化设置。

这是我现有的带有 Restsharp 版本 106.12.0 的自定义序列化程序类

public class CustomJsonSerializer : RestSharp.Serializers.ISerializer
    {
        public CustomJsonSerializer()
        {
            var restSerializer = new RestSharp.Serialization.Json.JsonSerializer();
            this.ContentType = restSerializer.ContentType;
        }
        public string ContentType { get; set; }
        public string DateFormat { get; set; }
        public string Namespace { get; set; }
        public string RootElement { get; set; }
        private JsonSerializerSettings SerializerSettings
        {
            get
            {
                JsonSerializerSettings settings = new JsonSerializerSettings();
                settings.Converters.Add(new StringEnumConverter());
                settings.Converters.Add(new DateTimeJsonConverter());
                settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                return settings;
            }
        }
        string RestSharp.Serializers.ISerializer.Serialize(object obj)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(obj, SerializerSettings);
        }
    }
C# asp.net JSON 枚举 restsharp

评论

0赞 dbc 8/24/2023
JSON 值无法转换为 SubExCore.Models.Enums.YearType。路径:$.body。年份类型 |行号:0 |BytePositionInLine: -- 此错误消息采用 System.Text.Json 生成的格式,而不是 Json.NET 格式。所以这是你实际使用的序列化程序。尝试申请,看看问题是否消失。[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter)]public SectionType? Section { get; set; }
0赞 dbc 8/24/2023
另外,您写道,新的 Restsharp 版本现在实现了来自 IRestSerializer 的 customserializer。 -- 请分享一个最小的可重现示例,说明您如何配置此 customserializer。
0赞 dbc 8/24/2023
顺便说一句,您的 JSON 看起来snake_case但您的 Json.NET 配置选项适用于驼峰大小写。您一定期望属性配置名称,但名称从何而来?我在 RestSharp 源代码中找不到它。[Map(ColumnName = "year_id"), Key]MapAttribute
0赞 Hakuna Matata 8/24/2023
@dbc:MapAttribute 是从 Attribute 抽象类中扩展出来的自定义类。
0赞 Hakuna Matata 8/24/2023
我知道使用枚举属性的 [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter)] 属性解决了这个问题。但是我们有数百个具有枚举和日期属性的模型,我希望自定义序列化程序在从 RestSharp.RestClient 获取响应的同时处理反序列化,而不是归因于项目中的所有模型。

答:

0赞 Power Mouse 8/24/2023 #1

还行。我简化了类,并使用提供的件为您创建了示例

void Main()
{
    string j = "{\"year_id\":\"2005\",\"year_type\":\"FirstYear\",\"section_type\":\"None\",\"college_name\":\"St. Alphores Govt College\",\"avg_pass\":89}";
    JsonConvert.DeserializeObject(j, SerializerSettings).Dump();
}

public class YearBook
{
    [JsonProperty("year_id")]
    public int Year { get; set; }

    [JsonProperty("year_type")]
    public YearType YearType { get; set; }

    [JsonProperty("section_type")]
    public SectionType? Section { get; set; }

    [JsonProperty("college_name")]
    public string CollegeName { get; set; }

    [JsonProperty("avg_pass")]
    public decimal AvgPass { get; set; }
}

public enum YearType
{
    FirstYear,
    SecondYear,
    ThirdYear
}

public enum SectionType
{
     None,
     MIT,
     BIT
}

private JsonSerializerSettings SerializerSettings
{
    get
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new StringEnumConverter());
        settings.Converters.Add(new DateTimeJsonConverter());
        settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        return settings;
    }
}

class DateTimeJsonConverter : IsoDateTimeConverter
{
    public DateTimeJsonConverter()
    {
        base.DateTimeFormat = "yyyy-MM-dd";
    }
}

如您所见,字符串响应按预期反序列化为对象:

enter image description here

评论

0赞 Hakuna Matata 8/24/2023
谢谢你的努力。正如我所提到的,我们正在使用 RestSharp 客户端来获取响应并序列化/反序列化 json 数据。使用 JsonConvert.DeserializeObject(j, SerializerSettings) 也对我有用。RestSharp 可以选择编写自定义序列化/反序列化方法。升级后,这些方法已弃用。如果你能在 RestSharp 中提供相同的序列化方式,将会非常受欢迎。
0赞 Alexey Zimarev 9/20/2023 #2

Power Mouse 的答案告诉您如何配置 NewtonsoftJson 来处理问题的 JSON 和模型。

为了将它与 RestSharp 一起使用,您需要告诉它使用这些设置。

假设你有一个用于某个 API 客户端的类,它可能看起来像

class SomeApiClient {
    readonly IRestClient _client;

    public SomeApiClient() {
        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new StringEnumConverter());
        settings.Converters.Add(new DateTimeJsonConverter());
        settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        var options = new RestClientOptions { ... something here };
        _client = new RestClient(
            options, 
            configureSerialization: cfg => cfg.UseNewtonsoftJson(settings)
        );
    }
}

class DateTimeJsonConverter : IsoDateTimeConverter
{
    public DateTimeJsonConverter()
    {
        base.DateTimeFormat = "yyyy-MM-dd";
    }
}

文档中对此进行了描述,只需查看即可。