枚举类型的 RestSharp 反序列化 属性
RestSharp deserialization of Enum Type Property
我有对象
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 消息 'Specified cast is not valid'。
我尝试将 json 字符串中的 YAxisPosition 值更改为字符串“1”或 "Left" 它总是给我同样的错误,直到我从 [= 中删除 属性 YAxisPosition 34=] 字符串.
我可能遗漏了一些东西(枚举属性 属性 或类似的东西)。
请帮助我找到一种方法,以便我可以使用 RestSharp 序列化和反序列化包含枚举类型 属性 的对象。
注意:我尝试使用 NewtonSoft 成功进行序列化和反序列化。但我不想让我的 Web API 客户端依赖于 NetwonSoft,因为我已经在使用 RestSharp。
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();
方案二:使用nuget包来使用JSON.NET
与其执行所有这些操作并让自定义 JSON 序列化程序遍布您的项目,不如使用这个 nuget 包:https://www.nuget.org/packages/RestSharp.Newtonsoft.Json。它允许您使用默认在内部使用 Newtonsoft.JSON 的继承 RestRequest 对象,如下所示:
var request = new RestSharp.Newtonsoft.Json.RestRequest(); // Uses JSON.NET
另一个选项是像这样在每次请求时设置它:
var request = new RestRequest();
request.JsonSerializer = new NewtonsoftJsonSerializer();
免责声明: 在对项目中的自定义序列化程序感到沮丧之后,我创建了这个项目。我创建它是为了保持整洁,并希望帮助其他想要向后兼容 v103 之前工作的 RestSharp 代码的人。
我在 PocoJsonSerializerStrategy
的帮助下开始工作。 RestSharp 允许您指定自己的 serialization/deserialization 策略,因此我创建了自己的策略来为我处理枚举:
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);
}
}
现在您可以将此 class 的对象传递给 SimpleJson.DeserializeObject
调用,这样您的枚举将得到优雅处理:
SimpleJson.DeserializeObject<JsonObject>(Response.Content, Strategy);
已找到此问题的解决方案:
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 class 到 serialize/deserialize 枚举。
如果您使用 Enumeration class pattern,则可以使用 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; }
}
我有对象
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 消息 'Specified cast is not valid'。
我尝试将 json 字符串中的 YAxisPosition 值更改为字符串“1”或 "Left" 它总是给我同样的错误,直到我从 [= 中删除 属性 YAxisPosition 34=] 字符串.
我可能遗漏了一些东西(枚举属性 属性 或类似的东西)。
请帮助我找到一种方法,以便我可以使用 RestSharp 序列化和反序列化包含枚举类型 属性 的对象。
注意:我尝试使用 NewtonSoft 成功进行序列化和反序列化。但我不想让我的 Web API 客户端依赖于 NetwonSoft,因为我已经在使用 RestSharp。
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();
方案二:使用nuget包来使用JSON.NET
与其执行所有这些操作并让自定义 JSON 序列化程序遍布您的项目,不如使用这个 nuget 包:https://www.nuget.org/packages/RestSharp.Newtonsoft.Json。它允许您使用默认在内部使用 Newtonsoft.JSON 的继承 RestRequest 对象,如下所示:
var request = new RestSharp.Newtonsoft.Json.RestRequest(); // Uses JSON.NET
另一个选项是像这样在每次请求时设置它:
var request = new RestRequest();
request.JsonSerializer = new NewtonsoftJsonSerializer();
免责声明: 在对项目中的自定义序列化程序感到沮丧之后,我创建了这个项目。我创建它是为了保持整洁,并希望帮助其他想要向后兼容 v103 之前工作的 RestSharp 代码的人。
我在 PocoJsonSerializerStrategy
的帮助下开始工作。 RestSharp 允许您指定自己的 serialization/deserialization 策略,因此我创建了自己的策略来为我处理枚举:
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);
}
}
现在您可以将此 class 的对象传递给 SimpleJson.DeserializeObject
调用,这样您的枚举将得到优雅处理:
SimpleJson.DeserializeObject<JsonObject>(Response.Content, Strategy);
已找到此问题的解决方案:
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 class 到 serialize/deserialize 枚举。
如果您使用 Enumeration class pattern,则可以使用 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; }
}