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

时间:2015-09-29 17:30:33

标签: c# json serialization asp.net-web-api 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属性的大型列表。)

3 个答案:

答案 0 :(得分:17)

如果您能够将Json的{​​{1}}属性类型从Person更改为string,那么您将获得所需的结果。

JRaw

或者,您可以保留public class Person { public string FirstName { get; set;} public string LastName { get; set;} public JRaw Json { get; set;} } 属性,并添加string属性以用作序列化的代理:

JRaw

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

答案 1 :(得分:1)

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

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);
    }
}

现在,如果您使用Json装饰[JsonConverter(typeof(StringToJsonConverter))]属性,则可以执行以下操作:

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

var s = JsonConvert.SerializeObject(obj);

得到这个:

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

这是{{3}}

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

答案 2 :(得分:0)

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

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