2012-02-28 25 views
18

Khi sử dụng Json.Net, tôi hiểu cách lấy thuộc tính $ type vào json được kết xuất, nhưng có cách nào để thay đổi tên trường đó không? Tôi cần sử dụng "__type" thay vì "$ type".

+0

Tôi cũng cần điều này, ví dụ [JSON-LD] (http://json-ld.org) sử dụng '@ type' –

Trả lời

12

Có vẻ như mã này được mã cứng là public const string TypePropertyName = "$type"; trong số Newtonsoft.Json.Serialization.JsonTypeReflector thật không may là lớp tĩnh bên trong.

Tôi cần bản thân mình và điều duy nhất tôi có thể nghĩ là có phiên bản sửa đổi tùy chỉnh của json.net. Đó là tất nhiên là một pita lớn.

+4

Thật không may, tôi đã hoàn toàn từ bỏ con đường tôi đã đi xuống vì Json.Net khó sử dụng như thế nào trong nhiều trường hợp. Đây chỉ là một ví dụ. –

+0

Tôi là chính tôi đang tìm kiếm cách tôi ở phía máy chủ, được viết i C# và sử dụng Json.NET, có thể deserialize JSON được gửi từ một ứng dụng Android bằng cách sử dụng Jackson. Trong Jackson tôi có thể thiết lập để sử dụng "$ loại", nhưng nó không hoạt động anyway. – Ted

13

http://json.codeplex.com/workitem/22429

"Tôi thà giữ $ gõ cứng mã hoá và nhất quán."

Phù hợp với những gì tôi tự hỏi?

http://json.codeplex.com/workitem/21989

Tôi thà không - Tôi nghĩ rằng đây là quá cụ thể đối với tôi và tôi không muốn đi quá nhiệt tình với các thiết lập. Tại một số điểm, tôi có thể sẽ thực hiện điều này - http://json.codeplex.com/workitem/21856 - cho phép mọi người đọc/ghi có thuộc tính meta trong JSON và bạn có thể reimplement xử lý tên kiểu với tên thuộc tính mới. Tùy chọn khác chỉ là sửa đổi mã nguồn cho chính bạn để có tên thuộc tính đó.

Đây là giải pháp của tôi ...

json.Replace("\"$type\": \"", "\"type\": \""); 
+0

Giải pháp của bạn thật tuyệt vời!^_^ –

+0

Xem thêm: https://github.com/JamesNK/Newtonsoft.Json/issues/1331 – manuc66

3

Chúng tôi đã có một nhu cầu cho điều này vì vậy tôi đã tạo ra một JsonReader tùy chỉnh. Chúng tôi đang sử dụng phần còn lại trong các dịch vụ web MS của chúng tôi với các mô hình dữ liệu phức tạp và cần thiết để thay thế thuộc tính "__type" bằng "$ type".

class MSJsonReader : JsonTextReader 
{ 
    public MSJsonTextReader(TextReader reader) : base(reader) { } 

    public override bool Read() 
    { 
     var hasToken = base.Read(); 

     if (hasToken && base.TokenType == JsonToken.PropertyName && base.Value != null && base.Value.Equals("__type")) 
      base.SetToken(JsonToken.PropertyName, "$type"); 

     return hasToken; 
    } 
} 

Đây là cách chúng tôi sử dụng.

using(JsonReader jr = new MSJsonTextReader(sr)) 
{ 
    JsonSerializer s = new JsonSerializer(); 
    s.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat; 
    s.NullValueHandling = NullValueHandling.Ignore; 
    s.TypeNameHandling = TypeNameHandling.Auto; // Important! 
    s.Binder = new MSRestToJsonDotNetSerializationBinder("Server.DataModelsNamespace", "Client.GeneratedModelsNamespace"); 

    T deserialized = s.Deserialize<T>(jr); 

    return deserialized; 
} 

Đây là MSRestToJsonDotNetSerializationBinder hoàn thành khả năng tương thích giữa phần còn lại MS và Json.Net.

class MSRestToJsonDotNetSerializationBinder : System.Runtime.Serialization.SerializationBinder 
{ 
    public string ServiceNamespace { get; set; } 
    public string LocalNamespace { get; set; } 

    public MSRestToJsonDotNetSerializationBinder(string serviceNamespace, string localNamespace) 
    { 
     if (serviceNamespace.EndsWith(".")) 
      serviceNamespace = serviceNamespace.Substring(0, -1); 

     if(localNamespace.EndsWith(".")) 
      localNamespace = localNamespace.Substring(0, -1); 

     ServiceNamespace = serviceNamespace; 
     LocalNamespace = localNamespace; 
    } 

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName) 
    { 
     assemblyName = null; 
     typeName = string.Format("{0}:#{1}", serializedType.Name, ServiceNamespace); // MS format 
    } 

    public override Type BindToType(string assemblyName, string typeName) 
    { 
     string jsonDotNetType = string.Format("{0}.{1}", LocalNamespace, typeName.Substring(0, typeName.IndexOf(":#"))); 
     return Type.GetType(jsonDotNetType); 
    } 
} 
1

Có một tùy chọn khác cho phép tuần tự hóa tên thuộc tính loại tùy chỉnh trong Json.NET. Ý tưởng không viết thuộc tính mặc định là $type, nhưng giới thiệu tên loại là thuộc tính của lớp đó.

Giả sử chúng ta có một lớp Location:

public class Location 
{ 
    public double Latitude { get; set; } 

    public double Longitude { get; set; } 
} 

tiên, chúng ta cần phải giới thiệu loại tên thuộc tính và sửa đổi các lớp như thể hiện dưới đây:

public class Location 
{ 
    [JsonProperty("__type")] 
    public string EntityTypeName 
    { 

     get 
     { 
      var typeName = string.Format("{0}, {1}", GetType().FullName, GetType().Namespace); 
      return typeName; 
     } 
    } 

    public double Latitude { get; set; } 

    public double Longitude { get; set; } 
} 

Sau đó, thiết lập JsonSerializerSettings.TypeNameHandling-TypeNameHandling.None để deserializer bỏ qua việc hiển thị thuộc tính mặc định $type.

Vậy đó.

Ví dụ

var point = new Location() { Latitude = 51.5033630, Longitude = -0.1276250 }; 

var jsonLocation = JsonConvert.SerializeObject(point, new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.None, //do not write type property(!) 
}); 
Console.WriteLine(jsonLocation); 

quả

{"__type":"Namespace.Location, Namespace","Latitude":51.503363,"Longitude":-0.127625} 
+0

Tôi không thấy cách deserializing sẽ xác định loại chính xác với giải pháp của bạn. Bạn có thể giải thích? –

+0

Để deserialize, hãy thử 'JsonCreationConverter', ví dụ: xem http://stackoverflow.com/questions/8030538 – xmedeko

2

khi tuần tự, có một cách tốt đẹp để ghi đè lên các tên thuộc tính:

public class CustomJsonWriter : JsonTextWriter 
{ 
    public CustomJsonWriter(TextWriter writer) : base(writer) 
    { 
    } 

    public override void WritePropertyName(string name, bool escape) 
    { 
     if (name == "$type") name = "__type"; 
     base.WritePropertyName(name, escape); 
    } 
} 

var serializer = new JsonSerializer(); 
var writer = new StreamWriter(stream) { AutoFlush = true }; 
serializer.Serialize(new CustomJsonWriter(writer), objectToSerialize); 

tôi đã không cố gắng deserialization được nêu ra, nhưng trong trường hợp xấu nhất tôi có thể sử dụng:

json.Replace("\"__type": \"", "\"type\": \"$type\"); 
2

Tôi phải làm điều này cho API REST REST của tôi là Angular.js disregards tên trường bắt đầu bằng ký hiệu đô la ($).

Vì vậy, đây là giải pháp đổi tên $type thành __type cho toàn bộ API Web và hoạt động cả hai cho việc tuần tự hóa cách ly hóa.

Để có thể sử dụng một tùy chỉnh JsonWriter và một tùy chỉnh JsonReader (như đề xuất trong câu trả lời khác cho câu hỏi này), chúng ta phải kế thừa JsonMediaTypeFormatter và ghi đè lên các phương pháp tương ứng:

internal class CustomJsonNetFormatter : JsonMediaTypeFormatter 
{ 
    public override JsonReader CreateJsonReader(Type type, Stream readStream, Encoding effectiveEncoding) 
    { 
     return new CustomJsonReader(readStream, effectiveEncoding); 
    } 

    public override JsonWriter CreateJsonWriter(Type type, Stream writeStream, Encoding effectiveEncoding) 
    { 
     return new CustomJsonWriter(writeStream, effectiveEncoding); 
    } 

    private class CustomJsonWriter : JsonTextWriter 
    { 
     public CustomJsonWriter(Stream writeStream, Encoding effectiveEncoding) 
      : base(new StreamWriter(writeStream, effectiveEncoding)) 
     { 
     } 

     public override void WritePropertyName(string name, bool escape) 
     { 
      if (name == "$type") name = "__type"; 
      base.WritePropertyName(name, escape); 
     } 
    } 

    private class CustomJsonReader : JsonTextReader 
    { 
     public CustomJsonReader(Stream readStream, Encoding effectiveEncoding) 
      : base(new StreamReader(readStream, effectiveEncoding)) 
     { 
     } 

     public override bool Read() 
     { 
      var hasToken = base.Read(); 
      if (hasToken && TokenType == JsonToken.PropertyName && Value != null && Value.Equals("__type")) 
      { 
       SetToken(JsonToken.PropertyName, "$type"); 
      } 
      return hasToken; 
     } 
    } 
} 

Trong số tất nhiên bạn cần đăng ký trình định dạng tùy chỉnh trong số WebApiConfig của mình. Vì vậy, chúng tôi thay thế trình định dạng Json.NET mặc định bằng tùy chỉnh của chúng tôi:

config.Formatters.Remove(config.Formatters.JsonFormatter); 
config.Formatters.Add(new CustomJsonNetFormatter()); 

Xong.

0

Bạn cũng có thể làm theo cách này:

[JsonConverter(typeof(JsonSubtypes), "ClassName")] 
public class Annimal 
{ 
    public virtual string ClassName { get; } 
    public string Color { get; set; } 
} 

Bạn sẽ cần bộ chuyển đổi JsonSubtypes đó không phải là một phần của dự án Newtonsoft.Json.

Các vấn đề liên quan