Json.NET – 阻止重新序列化已经序列化的属性

在ASP.NET Web API应用程序中,我正在使用的一些模型包含一大块ad-hoc JSON,仅在客户端有用。 在服务器上,它只是作为字符串进出关系数据库。 性能是关键,根本不需要处理JSON字符串服务器端。

所以在C#中,想象一个像这样的对象:

new Person { FirstName = "John", LastName = "Smith", Json = "{ \"Age\": 30 }" }; 

默认情况下,Json.NET会像这样序列化这个对象:

 { "FirstName": "John", "LastName": "Smith", "Json": "{ \"Age\": 30 }" } 

我希望能够指示Json.NET假设Json属性已经是序列化表示,因此它不应该重新序列化,并且生成的JSON应该如下所示:

 { "FirstName": "John", "LastName": "Smith", "Json": { "Age": 30 } } 

理想情况下,这适用于两个方向,即在POST JSON表示时,它将自动反序列化为上面的C#表示。

使用Json.NET实现这一目标的最佳机制是什么? 我需要自定义JsonConverter吗? 是否有一个更简单的基于属性的机制? 效率很重要; 重点是跳过序列化开销,这可能是一个微优化,但为了论证,让我们假设它不是。 (可能会返回包含大量Json属性的大列表。)

如果您能够将Person上的Json属性类型从string更改为JRaw那么您将获得所需的结果。

 public class Person { public string FirstName { get; set;} public string LastName { get; set;} public JRaw Json { get; set;} } 

或者,您可以保留string属性,并添加一个JRaw属性以用作序列化的代理:

 public class Person { public string FirstName { get; set;} public string LastName { get; set;} [JsonIgnore] public string Json { get; set; } [JsonProperty("Json")] private JRaw MyJson { get { return new JRaw(this.Json); } set { this.Json = value.ToString(); } } } 

无论哪种方式,序列化和反序列化都可以按照您的要求运行。

我不确定这是一件非常有用的事情,但您可以创建一个这样的自定义转换器:

 public class StringToJsonConverter : JsonConverter { public override bool CanConvert(Type t) { throw new NotImplementedException(); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var o = JsonConvert.DeserializeObject(value.ToString()); serializer.Serialize(writer,o); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var o = serializer.Deserialize(reader); return JsonConvert.SerializeObject(o); } } 

现在如果你用[JsonConverter(typeof(StringToJsonConverter))]装饰你的Json属性,你可以这样做:

 var obj = new Person { FirstName = "John", LastName = "Smith", Json = "{ \"Age\": 30 }" }; var s = JsonConvert.SerializeObject(obj); 

得到这个:

 {"FirstName":"John","LastName":"Smith","Json":{"Age":30}} 

这是一个小提琴

但是在我的小提琴中有一个注意事项,我是围绕序列化和反序列化的,但Json属性中的值并不完全相同。 为什么? 因为花括号周围的额外空间在此过程中被剥离了。 当然,它们不是(或不应该)重要的。

我不确定是否有办法跳过序列化。 这是一个以简单方式序列化和反序列化的选项。

 public class Person { public string FirstName = "John"; public string LastName = "Smith"; [JsonIgnore] public string Json = "{ \"Age\": 30 }"; public JObject JsonP { get { return JsonConvert.DeserializeObject(Json); } } }