我正在使用JSON.NET开发一个ASP.NET应用程序,该应用程序与第三方REST API连接。 API以下列格式返回JSON:
[
{
user: {
id: 12345,
first_name: "John",
last_name: "Smith",
created_at: "11/12/13Z00:00:00"
}
},
{
user: {
id: 12346,
first_name: "Bob",
last_name: "Adams",
created_at: "12/12/13Z00:00:00"
}
}
]
user
字段是多余的,但我无法控制API,所以我必须忍受它。我目前正在使用以下代码反序列化JSON:
// Deserialize
var responseBody = JsonConvert.DeserializeObject<IEnumerable<UserWrapper>>(responseString);
// Access Properties
foreach (var userWrapper in responseBody)
{
var firstName = userWrapper.User.FirstName
}
// Model classes
public class UserWrapper
{
[JsonProperty(PropertyName = "user")]
public User User { get; set; }
}
public class User
{
[JsonProperty(PropertyName = "id")]
public string ID { get; set; }
[JsonProperty(PropertyName = "first_name")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "last_name")]
public string LastName { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
}
让包装器类有点难看。所以我的问题是:
有没有办法使用JSON.NET消除包装类?
答案 0 :(得分:1)
是的,您可以通过为User
类创建自定义转换器并在反序列化期间使用它来执行此操作。转换器代码可能如下所示:
class UserConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(User));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject wrapper = JObject.Load(reader);
return wrapper["user"].ToObject<User>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("user");
writer.WriteRawValue(JsonConvert.SerializeObject(value));
writer.WriteEndObject();
}
}
保持User
类完全按照您的定义(包含所有JsonProperty
个装饰)。
然后,您可以反序列化您的JSON并访问如下属性:
var users = JsonConvert.DeserializeObject<List<User>>(responseString, new UserConverter());
foreach (var user in users)
{
var firstName = user.FirstName
// etc...
}
不再需要UserWrapper
类,可以将其删除。
修改强>
重要提示:如果您使用User
属性装饰[JsonConverter]
类,则上述解决方案将 NOT 有效。这是因为写入的自定义转换器使用序列化程序的第二个副本来处理User
反序列化,一旦我们下降到达真实用户数据。如果你装饰这个类,那么序列化器的所有副本都会尝试使用转换器,你最终会得到一个自引用循环。
如果您更愿意使用[JsonConverter]
属性,那么自定义转换器类必须手动处理User
类的所有属性的反序列化。采用这种方法,代码看起来就像这样:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject wrapper = JObject.Load(reader);
JToken user = wrapper["user"];
return new User
{
ID = user["id"].Value<string>(),
FirstName = user["first_name"].Value<string>(),
LastName = user["last_name"].Value<string>(),
CreatedAt = user["created_at"].Value<DateTime>()
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
User user = (User)value;
writer.WriteStartObject();
writer.WritePropertyName("user");
writer.WriteStartObject();
writer.WritePropertyName("id");
writer.WriteValue(user.ID);
writer.WritePropertyName("first_name");
writer.WriteValue(user.FirstName);
writer.WritePropertyName("last_name");
writer.WriteValue(user.LastName);
writer.WritePropertyName("created_at");
writer.WriteValue(user.CreatedAt);
writer.WriteEndObject();
writer.WriteEndObject();
}
这种方法的一个明显问题是您牺牲了一点可维护性:如果您为User
课程添加了更多属性,则必须记住将UserConverter
更改为匹配。< / p>