使用 JSON.net 处理(反)序列化的主数据
Handling Master Data on (De-)Serialization with JSON.net
使用 JSON.NET 我被 MasterData 关于 GET 和 POST 操作的问题困住了。
使用电影的例子,JSON我可以在反序列化之前进行 GET 操作如下:
{
“movie”: {
“name”:”bad boys”,
”genre”: {
“id”:"1",
”name”:”thriller”
}
}
}
但是,在 POST 操作中,我想构造一个如下所示的序列化字符串:
{
“movie”: {
“name”:”bad boys”,
”genre”:"1"
}
}
如您所见,使用 GET 操作我需要反序列化整个对象,而在序列化 POST 时我只需要添加 Id,但具有相同的 JsonPropertyName。
获得这种情况的最干净的方法是什么?我一直在尝试使用 IContractResolver 和 IReferenceResolver,但它们都没有让我到达那里。也一直在尝试使用 propertynames 作为以下示例:
[JsonProperty(PropertyName = "genre")]
public Genre Genre { get; set; }
[JsonProperty(PropertyName = "genre")]
public string GenreId { get { return Genre != null ? Genre.Id : 0; } }
我也试过使用 ShouldSerialize[MemberName] 和 ShouldDeserialize[MemberName] 的情况,但是那些给出了一个异常,说我不能使用同名的两个属性,这在某种程度上是合乎逻辑的。
现在,我唯一的想法是使用 DTO 进行序列化,但我宁愿选择比该解决方案更干净的东西。欢迎大家提出建议!
为此使用 custom converter。您想要检查 genre
属性的类型并将其读取为 object
或 int
.
在我看来,使用 DTO 是最干净的解决方案。由于 GET/POST 的模型不同,理想情况下您需要两个单独的模型。我滥用 NullValueHandling.Ignore
序列化程序设置意味着您可以在两种情况下使用相同的模型,前提是您不介意总是在 Genre
上使用 Id
属性:
class MovieJsonWrapper
{
[JsonProperty("movie")]
public Movie Movie { get; set; }
}
class Movie
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("genre")]
public Genre Genre { get; set; }
}
class Genre
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
然后我们可以将其用于:
var movie = new Movie
{
Name = "bad boys",
Genre = new Genre
{
Id = "1"
}
};
var movieJsonWrapper = new MovieJsonWrapper { Movie = movie };
var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
var json = JsonConvert.SerializeObject(movieJsonWrapper, jsonSerializerSettings);
这将产生以下内容:
{
"movie": {
"name": "bad boys",
"genre": {
"id": "1"
}
}
}
同样,我们可以反序列化 GET 响应:
var result = JsonConvert.DeserializeObject<MovieJsonWrapper>(raw);
如果您确实需要在发布时放弃流派上的 Id
属性,那么您将需要额外的模型。此解决方案减少了样板文件的数量。
您可以编写自定义转换器。
public class GenreConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Genre);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return JObject.Load(reader).ToObject<Genre>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var genre = value as Genre;
writer.WriteValue(genre.id);
}
}
您现在只需要使用 JsonConverter
属性
public class Movie
{
public string Name { get; set; }
[JsonConverter(typeof(GenreConverter))]
public Genre Genre { get; set; }
}
使用 JSON.NET 我被 MasterData 关于 GET 和 POST 操作的问题困住了。
使用电影的例子,JSON我可以在反序列化之前进行 GET 操作如下:
{
“movie”: {
“name”:”bad boys”,
”genre”: {
“id”:"1",
”name”:”thriller”
}
}
}
但是,在 POST 操作中,我想构造一个如下所示的序列化字符串:
{
“movie”: {
“name”:”bad boys”,
”genre”:"1"
}
}
如您所见,使用 GET 操作我需要反序列化整个对象,而在序列化 POST 时我只需要添加 Id,但具有相同的 JsonPropertyName。
获得这种情况的最干净的方法是什么?我一直在尝试使用 IContractResolver 和 IReferenceResolver,但它们都没有让我到达那里。也一直在尝试使用 propertynames 作为以下示例:
[JsonProperty(PropertyName = "genre")]
public Genre Genre { get; set; }
[JsonProperty(PropertyName = "genre")]
public string GenreId { get { return Genre != null ? Genre.Id : 0; } }
我也试过使用 ShouldSerialize[MemberName] 和 ShouldDeserialize[MemberName] 的情况,但是那些给出了一个异常,说我不能使用同名的两个属性,这在某种程度上是合乎逻辑的。
现在,我唯一的想法是使用 DTO 进行序列化,但我宁愿选择比该解决方案更干净的东西。欢迎大家提出建议!
为此使用 custom converter。您想要检查 genre
属性的类型并将其读取为 object
或 int
.
在我看来,使用 DTO 是最干净的解决方案。由于 GET/POST 的模型不同,理想情况下您需要两个单独的模型。我滥用 NullValueHandling.Ignore
序列化程序设置意味着您可以在两种情况下使用相同的模型,前提是您不介意总是在 Genre
上使用 Id
属性:
class MovieJsonWrapper
{
[JsonProperty("movie")]
public Movie Movie { get; set; }
}
class Movie
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("genre")]
public Genre Genre { get; set; }
}
class Genre
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
然后我们可以将其用于:
var movie = new Movie
{
Name = "bad boys",
Genre = new Genre
{
Id = "1"
}
};
var movieJsonWrapper = new MovieJsonWrapper { Movie = movie };
var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
var json = JsonConvert.SerializeObject(movieJsonWrapper, jsonSerializerSettings);
这将产生以下内容:
{
"movie": {
"name": "bad boys",
"genre": {
"id": "1"
}
}
}
同样,我们可以反序列化 GET 响应:
var result = JsonConvert.DeserializeObject<MovieJsonWrapper>(raw);
如果您确实需要在发布时放弃流派上的 Id
属性,那么您将需要额外的模型。此解决方案减少了样板文件的数量。
您可以编写自定义转换器。
public class GenreConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Genre);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return JObject.Load(reader).ToObject<Genre>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var genre = value as Genre;
writer.WriteValue(genre.id);
}
}
您现在只需要使用 JsonConverter
属性
public class Movie
{
public string Name { get; set; }
[JsonConverter(typeof(GenreConverter))]
public Genre Genre { get; set; }
}