RestSharp反序列化枚举类型属性

6
我有一个对象。
            var testTcc = new TrendingConfigurationConfigDto
            {
                TrendingConfigurationId =1,
                ConfigId = 1,
                DeviceId = 1,
                Selected = true,
                YAxisPosition = YAxisPosition.Left,
                Order = 1,
                Color = "#ffffff",
                Configuration = new BO.Shared.Dtos.List.ConfigurationListDto
                {
                    Id = 1,
                    Name = "configuration",
                    Alias = "configuationAlias",
                    EnableEdit = true,
                    IsBusinessItem = true
                },
                Device = new BO.Shared.Dtos.List.DeviceListDto
                {
                    Id = 1,
                    Name = "Device"
                }
            };

当我将其序列化为JSON时,如下所示:
var jsonTcc = SimpleJson.SerializeObject(testTcc);

它返回一个包含YAxisPosition = 1的JSON对象的字符串,当我尝试使用反序列化对其进行处理时。

testTcc = SimpleJson.DeserializeObject<TrendingConfigurationConfigDto>(jsonTcc);

出现了System.InvalidCastException异常,错误信息为“指定的强制转换无效”。

我尝试将json字符串中的YAxisPosition值更改为字符串“1”或“Left”,但始终会出现相同的错误,直到我从json字符串中删除了属性YAxisPosition。

可能我漏掉了某些东西(枚举属性上的特性或类似的内容)。

请帮我找到一种方法,使我能够使用RestSharp序列化和反序列化包含Enum类型属性的对象。

注意:我已经成功地使用NewtonSoft进行序列化和反序列化。但是,由于我已经在使用RestSharp,所以我不想让我的Web API客户端依赖于NetwonSoft。

4个回答

7
RestSharp在v103.0中删除了对JSON.NET的支持。默认的Json序列化程序不再兼容Json.NET。如果您想继续使用JSON.NET并保持向后兼容性,有几个选项可供选择。除此之外,JSON.NET具有更多功能,可能比现在RestSharp依赖的基本.NET序列化程序解决您的问题更好。
另外,您可以使用[EnumMember]属性来定义反序列化期间的自定义映射。
选项1:实现一个使用JSON.NET的自定义序列化程序
要使用Json.NET进行序列化,请复制此代码:
/// <summary>
/// Default JSON serializer for request bodies
/// Doesn't currently use the SerializeAs attribute, defers to Newtonsoft's attributes
/// </summary>
public class JsonNetSerializer : ISerializer
{
    private readonly Newtonsoft.Json.JsonSerializer _serializer;

    /// <summary>
    /// Default serializer
    /// </summary>
    public JsonSerializer() {
        ContentType = "application/json";
        _serializer = new Newtonsoft.Json.JsonSerializer {
            MissingMemberHandling = MissingMemberHandling.Ignore,
            NullValueHandling = NullValueHandling.Include,
            DefaultValueHandling = DefaultValueHandling.Include
        };
    }

    /// <summary>
    /// Default serializer with overload for allowing custom Json.NET settings
    /// </summary>
    public JsonSerializer(Newtonsoft.Json.JsonSerializer serializer){
        ContentType = "application/json";
        _serializer = serializer;
    }

    /// <summary>
    /// Serialize the object as JSON
    /// </summary>
    /// <param name="obj">Object to serialize</param>
    /// <returns>JSON as String</returns>
    public string Serialize(object obj) {
        using (var stringWriter = new StringWriter()) {
            using (var jsonTextWriter = new JsonTextWriter(stringWriter)) {
                jsonTextWriter.Formatting = Formatting.Indented;
                jsonTextWriter.QuoteChar = '"';

                _serializer.Serialize(jsonTextWriter, obj);

                var result = stringWriter.ToString();
                return result;
            }
        }
    }

    /// <summary>
    /// Unused for JSON Serialization
    /// </summary>
    public string DateFormat { get; set; }
    /// <summary>
    /// Unused for JSON Serialization
    /// </summary>
    public string RootElement { get; set; }
    /// <summary>
    /// Unused for JSON Serialization
    /// </summary>
    public string Namespace { get; set; }
    /// <summary>
    /// Content type for serialized content
    /// </summary>
    public string ContentType { get; set; }
}

并将其注册到您的客户端:
var client = new RestClient();
client.JsonSerializer = new JsonNetSerializer();

选项2:使用nuget包来使用JSON.NET

不必在项目中分散自定义的JSON序列化器,而是可以使用此nuget包https://www.nuget.org/packages/RestSharp.Newtonsoft.Json。它允许您使用继承的RestRequest对象,默认情况下使用Newtonsoft.JSON内部,如下所示:

var request = new RestSharp.Newtonsoft.Json.RestRequest(); // Uses JSON.NET

另一种选择是像这样在每个请求中设置它:
var request = new RestRequest();
request.JsonSerializer = new NewtonsoftJsonSerializer();

声明:我在将自定义序列化器放置在我的项目中感到困惑后创建了这个项目。我创建它的目的是保持项目整洁,并希望能够帮助那些希望实现与 RestSharp v103 之前版本代码向后兼容性的人。


1
虽然您已经开始在链接到您的项目时包含代码,但最好还是要披露您正在链接到自己的工作。请参见答案中自我推广的限制如何以社区友好的方式链接到外部资源?等。 - Paul Roub
感谢@PaulRoub提供的信息。我添加了免责声明。 - Adam
看起来上面的解决方案只适用于序列化请求。对于反序列化,它会回退到使用RestSharp内置的序列化器。 - Panji

3
找到了这个问题的解决方案:
private IRestClient GetRestClient()
        {
            return new RestClient(url)
                .AddDefaultHeader("Authorization", $"Bearer {token.AccessToken}")
                .AddDefaultHeader("Accept", "*/*")
                .AddDefaultHeader("Accept-Encoding", "gzip, deflate, br")
                .AddDefaultHeader("Connection", "close")
                .UseSystemTextJson(new JsonSerializerOptions
                {
                    Converters = { new JsonStringEnumConverter() }
                });
        }

即,指示 RestSharp 使用 System.Text.Json 序列化程序,然后指示序列化程序使用 JsonStringEnumConverter 类来序列化/反序列化枚举。

0
如果您正在使用枚举类模式,则可以使用JsonConverter方法。这意味着您需要创建一个自定义转换器,并在需要序列化的属性上使用JsonConverter属性。以下是示例:
using Newtonsoft.Json;
using System;

namespace MyAwesomeAPI
{
    public class EnumerationConverter<TEnum> : JsonConverter
        where TEnum : Enumeration
    {
        public override bool CanConvert(Type objectType) => objectType == typeof(TEnum);
        public override bool CanRead { get => true; }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var uknown = Enumeration.FromDisplayName<TEnum>("Unknown");
            if (reader.TokenType == JsonToken.Null)
            {
                return null;
            }

            if (reader.TokenType == JsonToken.String)
            {
                var enumText = reader.Value?.ToString();

                if (string.IsNullOrEmpty(enumText))
                {
                    return uknown;
                }

                try
                {
                    return Enumeration.FromDisplayName<TEnum>(enumText);
                }
                catch (Exception)
                {
                    return uknown;
                }
            }
            return uknown;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteValue(value.ToString());
        }
    }
}

我们的枚举看起来像这样:

public class CardType : Enumeration
{
    public static CardType Unknown = new(0, nameof(Unknown));
    public static CardType Amex = new(1, nameof(Amex));
    public static CardType Visa = new(2, nameof(Visa));
    public static CardType MasterCard = new(3, nameof(MasterCard));

    public CardType(int id, string name) : base(id, name)
    {
    }
}

最后一件事是将属性应用于属性。
public class CreditCardResponse
{
    [JsonProperty("card_number")]
    public string CardNumber { get; set; }
    [JsonProperty("card_type")]
    [JsonConverter(typeof(EnumerationConverter<CardType>))]
    public CardType CardType { get; set; }
}

0

PocoJsonSerializerStrategy 的帮助下,我让它工作了。RestSharp 允许您指定自己的序列化/反序列化策略,因此我创建了自己的策略来处理枚举:

public class HandleEnumsJsonSerializerStrategy : PocoJsonSerializerStrategy
{
  public override object DeserializeObject(object value, Type type)
  {
    if (type.IsEnum)
      return Enum.Parse(type, (string)value);
    else
      return base.DeserializeObject(value, type);
  }
}

现在,您可以将此类的对象传递给SimpleJson.DeserializeObject调用,就像这样,您的枚举将被优雅地处理:
SimpleJson.DeserializeObject<JsonObject>(Response.Content, Strategy);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接