2015-09-29 27 views
8

Trong một ứng dụng ASP.NET Web API, một số mô hình mà tôi đang làm việc có chứa một đoạn JSON đặc biệt chỉ hữu ích ở phía máy khách . Trên máy chủ, nó đơn giản đi vào và ra khỏi một cơ sở dữ liệu quan hệ dưới dạng một chuỗi. Hiệu suất là chìa khóa và có vẻ như vô nghĩa khi xử lý phía máy chủ chuỗi JSON.Json.NET - ngăn chặn tái tuần tự hóa một thuộc tính đã được tuần tự hóa

Vì vậy, trong C#, hãy tưởng tượng một đối tượng như thế này:

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

Theo mặc định, Json.NET sẽ serialize đối tượng này như sau:

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

Tôi muốn để có thể hướng dẫn Json.NET giả định rằng thuộc tính Json đã là một đại diện được tuần tự hóa, do đó nó không được sắp xếp lại và kết quả JSON sẽ giống như sau:

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

Lý tưởng nhất là hoạt động theo cả hai hướng, tức là khi POST biểu diễn JSON, nó sẽ tự động deserialize vào đại diện C# ở trên.

Cơ chế tốt nhất để đạt được điều này với Json.NET là gì? Tôi có cần tùy chỉnh JsonConverter không? Có một cơ chế dựa trên thuộc tính đơn giản hơn không? Hiệu quả vấn đề; toàn bộ vấn đề là bỏ qua hàng loạt đầu vào, trong đó có thể là một chút tối ưu hóa vi mô, nhưng vì lợi ích của đối số, hãy giả sử là không. (Có khả năng sẽ có danh sách lớn với cồng kềnh Json tính được trả lại.)

+0

Nếu thuộc tính của bạn 'Json' là một chuỗi, thì nó sẽ được tuần tự hóa thành chuỗi. Tôi không hoàn toàn chắc chắn vấn đề là gì. Chỉ cần serialize nó như là một chuỗi, lưu trữ nó trong cơ sở dữ liệu của bạn như là một chuỗi và deserialize nó trở lại như là một chuỗi. –

+0

Có lẽ tôi đã không giải thích rõ. Tôi đã thêm một mẫu JSON phụ để làm nổi bật sự khác biệt giữa những gì xảy ra theo mặc định và những gì tôi đang tìm kiếm để đạt được. –

+1

Nếu mã phía máy chủ của bạn đang nhận chuỗi JSON từ đâu đó mà bạn có thể kiểm soát, bạn sẽ tốt hơn rất nhiều trong việc khắc phục vấn đề đó hơn là cố gắng tìm ra giải pháp cho vấn đề này. Tuy nhiên, nếu nó đến từ một cái gì đó mà bạn không có quyền truy cập vào, nỗ lực đầu tiên của tôi sẽ là deserialize nó khi bạn nhận được nó từ bất cứ nguồn nào bạn lấy nó từ. Điều đó có thể được thực hiện với một deserializer tùy chỉnh. Không có đủ thông tin để đưa ra giải pháp tốt nhất cho bạn. – krillgar

Trả lời

13

Nếu bạn có thể thay đổi kiểu của Json tài sản trên Personstring-JRaw sau đó bạn sẽ nhận được kết quả mong muốn.

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

Ngoài ra, bạn có thể giữ string bất động sản, và thêm một tài sản JRaw sẽ được sử dụng như là một proxy cho serialization:

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

Dù bằng cách nào, cả hai serialization và deserialization sẽ làm việc như bạn đã yêu cầu .

+2

Tôi không biết về 'JRaw' và có vẻ phù hợp nhất với những gì tôi đang cố gắng giải quyết. Cảm ơn. –

+0

FWIW, vì câu trả lời này, tôi nghĩ câu hỏi này nên là câu hỏi mà câu hỏi "đã được hỏi" khác tham khảo. – HeyZiko

1

Tôi không chắc chắn đây chính là một điều hữu ích để làm, nhưng bạn có thể tạo ra một chuyển đổi tùy chỉnh như thế này:

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

Bây giờ nếu bạn trang trí bạn Json tài sản với [JsonConverter(typeof(StringToJsonConverter))], bạn có thể làm điều này:

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

var s = JsonConvert.SerializeObject(obj); 

Và có được điều này:

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

Dưới đây là một fiddle

Một lưu ý tuy nhiên trong fiddle của tôi, tôi tròn vấp ngã serialization và deserialization, nhưng các giá trị trong Json bất động sản không phải là giống hệt nhau. Tại sao? Bởi vì các khoảng trống xung quanh niềng răng xoăn của bạn đã bị loại bỏ trong quá trình này. Tất nhiên, họ không (hoặc không nên) đáng kể.

+0

Chăm sóc cử tri xuống để giải thích? Nó đạt được chính xác những gì OP yêu cầu. –

+0

Tôi có thể cho bạn biết đó không phải là tôi :) –

+0

Điều đó đã hiệu quả (+1). Nhưng theo quan điểm của bạn, tôi bắt đầu đặt câu hỏi về tính hữu dụng. Vì thuộc tính chỉ cần tồn tại như một chuỗi trên máy chủ, từ yêu cầu thô tới cơ sở dữ liệu và ngược lại, tôi đã hy vọng một số giải pháp không liên quan đến việc tuần tự hóa/deserializing. Nhưng như là một tài sản của một đối tượng cha mẹ tôi bắt đầu nghĩ rằng đó là một trong hai không thể hoặc không có giá trị nỗ lực. –

0

Tôi không chắc chắn có cách nào để bỏ qua phần tuần tự hóa. Đây là một tùy chọn để tuần tự hóa và deserialize một cách đơn giản.

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); } } 
} 
Các vấn đề liên quan