C# Json.NET-防止重新序列化已序列化的属性

C# Json.NET-防止重新序列化已序列化的属性,c#,json,serialization,asp.net-web-api,json.net,C#,Json,Serialization,Asp.net Web Api,Json.net,在ASP.NET Web API应用程序中,我正在使用的一些模型包含一块只在客户端有用的即席JSON。在服务器上,它只是作为字符串进出关系数据库。性能是关键,处理JSON字符串服务器端似乎毫无意义 在C#中,想象这样一个物体: new Person { FirstName = "John", LastName = "Smith", Json = "{ \"Age\": 30 }" }; { "FirstName": "John", "LastName":

在ASP.NET Web API应用程序中,我正在使用的一些模型包含一块只在客户端有用的即席JSON。在服务器上,它只是作为字符串进出关系数据库。性能是关键,处理JSON字符串服务器端似乎毫无意义

在C#中,想象这样一个物体:

new Person
{
    FirstName = "John",
    LastName = "Smith",
    Json = "{ \"Age\": 30 }"
};
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": "{ \"Age\": 30 }"
}
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": {
        "Age": 30
    }
}
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.NET将序列化此对象,如下所示:

new Person
{
    FirstName = "John",
    LastName = "Smith",
    Json = "{ \"Age\": 30 }"
};
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": "{ \"Age\": 30 }"
}
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": {
        "Age": 30
    }
}
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.NET假设
Json
属性已经是一个序列化表示,因此它不应该重新序列化,结果Json应该如下所示:

new Person
{
    FirstName = "John",
    LastName = "Smith",
    Json = "{ \"Age\": 30 }"
};
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": "{ \"Age\": 30 }"
}
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": {
        "Age": 30
    }
}
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表示时,它将自动反序列化为上面的C#表示


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

我不确定这是否是一件有用的事情,但您可以创建如下自定义转换器:

new Person
{
    FirstName = "John",
    LastName = "Smith",
    Json = "{ \"Age\": 30 }"
};
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": "{ \"Age\": 30 }"
}
{
    "FirstName": "John",
    "LastName": "Smith",
    "Json": {
        "Age": 30
    }
}
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<JObject>(Json); } }
}
公共类人物
{
公共字符串FirstName=“John”;
公共字符串LastName=“Smith”;
[JsonIgnore]
公共字符串Json=“{\'Age\”:30}”;
PublicJobject JsonP{get{return JsonConvert.DeserializeObject(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(); }
    }        
}

无论哪种方式,序列化和反序列化都将按照您的要求工作。

如果您的属性
Json
是字符串,则应将其序列化为字符串。我不完全确定问题出在哪里。只是将它序列化为字符串,作为字符串存储在数据库中,然后反序列化为字符串。也许我没有解释清楚。我添加了一个额外的JSON示例,以强调默认情况下发生的情况与我希望实现的情况之间的差异。如果您的服务器端代码从您可以控制的地方获取JSON字符串,那么您最好解决这部分问题,而不是尝试提出解决方案。然而,如果它来自您无法访问的内容,我的第一个尝试是当您从任何来源获取它时反序列化它。这可以通过自定义反序列化器完成。没有足够的信息为您提供最佳解决方案。我认为唯一的方法是使用自定义转换器,您需要获取JSON字符串,将其反序列化为JSON对象,然后将其添加到序列化值中,如果您希望它序列化“内联”JSON。您想解释一下吗?它完全达到了OP的要求。我可以告诉你,不是我:)起作用了(+1)。但就你而言,我开始质疑它的有用性。由于属性只需要作为字符串存在于服务器上,从原始请求到数据库,反之亦然,因此我希望找到一种根本不涉及序列化/反序列化的解决方案。但作为父对象的属性,我开始认为这要么不可能,要么不值得努力。我不知道
JRaw
,看起来最适合我试图解决的问题。谢谢。FWIW,因为这个答案,我认为这个问题应该是另一个“已经被问过”的问题所参考的问题。