2015-09-25 148 views
1

在我的Web API項目,現在我跳過空值。因此,返回json忽略空值並打印屬性。JSON序列NullValueHandling屬性

在Global.asax文件:

//manage the null in the response 
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; 
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; 

不過,我想通過更換空值 「 - 」。但是,我不希望使用數據成員屬性,每個屬性...

[DefaultValue("-")]. 

我有超過10班在我的項目...所以,這是不是最完美的解決方案。

祝是一個簡單的解決方案,並適用於任何轉換,與從在Global.asax

實施例的空值一樣。

public class User 
{ 
    public string user { get; set; } 

    public string name { get; set; } 

    public string dni { get; set; } 
} 

時存在的所有數據,我的服務回報

{ 
    "user": "usertest", 
    "name": "nametest", 
    "dni": "123456789" 
} 

但是,DNI時,不存在,所以響應,這

{ 
    "user": "usertest", 
    "name": "nametest", 
    "dni": "" 
} 

,我想回應如下

{ 
    "user": "usertest", 
    "name": "nametest", 
    "dni": "-" 
} 
+0

你介意你澄清一個小問題?你的意思是你想跳過寫出當前值與默認值相匹配的成員,或者在寫入具有空值的成員時,將寫入的值替換爲默認值? – dbc

+0

另外,你的意思是你不想爲每個屬性使用'[DefaultValue]'? ['DefaultValueAttribute'](https://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute%28v=vs.110%29.aspx)不是數據成員屬性,它用於很多事情包括財產編輯。 – dbc

+0

好,已編輯。我不想使用默認屬性。 [默認值(」-」)]。我只需要一個簡單而優雅的方法來爲所有屬性json序列化程序設置DefaultValue。 – Makito

回答

-1

您可以在globals.asax中註冊一個轉換器。您可以添加如下內容:

config.Formatters.JsonFormatter.SerializerSettings.Converters.add(new NullHandlerConverter());

其中,NullHandlerConverter是您需要編寫的自定義轉換器。

編輯:Brian是對的。無法使用轉換器,因爲沒有辦法讓它們調用null值。

+1

不幸的是,'JsonConverter'不能用於此,因爲在序列化期間轉換器不會被調用爲空值。小提琴:https://dotnetfiddle.net/LmcroE –

0

我不建議這樣做。問題是如果你的字符串值屬性恰好與你的「空值」"-"具有相同的值,那麼序列化時就會失去信息,即屬性是否實際爲空。

話雖這麼說,你可以用一個ContractResolver通過重寫JsonProperty.ValueProvider字符串值的屬性做到這一點:

public class StringRemappingContractResolver : DefaultContractResolver 
{ 
    static readonly object NullValue; 

    static StringRemappingContractResolver() { NullValue = new object(); } 

    readonly Dictionary<object, object> map; 
    readonly ILookup<object, object> reverseMap; 

    public StringRemappingContractResolver() : this(new KeyValuePair<object, object> [] { new KeyValuePair<object, object>(null, "-")}) 
    { 
    } 

    public StringRemappingContractResolver(IEnumerable<KeyValuePair<object, object>> map) 
    { 
     if (map == null) 
      throw new ArgumentNullException("map"); 
     this.map = map.ToDictionary(p => p.Key ?? NullValue, p => p.Value); 
     this.reverseMap = map.ToLookup(p => p.Value ?? NullValue, p => p.Key); 
    } 

    class StringRemappingValueProvider : IValueProvider 
    { 
     readonly IValueProvider baseProvider; 
     readonly Dictionary<object, object> map; 
     readonly ILookup<object, object> reverseMap; 

     public StringRemappingValueProvider(IValueProvider baseProvider, Dictionary<object, object> map, ILookup<object, object> reverseMap) 
     { 
      if (baseProvider == null) 
       throw new ArgumentNullException("baseProvider"); 
      this.baseProvider = baseProvider; 
      this.map = map; 
      this.reverseMap = reverseMap; 
     } 

     #region IValueProvider Members 

     public object GetValue(object target) 
     { 
      var value = baseProvider.GetValue(target); 
      object mapped; 
      if (map.TryGetValue(value ?? NullValue, out mapped)) 
       value = mapped; 
      return value; 
     } 

     public void SetValue(object target, object value) 
     { 
      foreach (var mapped in reverseMap[value ?? NullValue]) 
      { 
       // Use the first. 
       value = mapped; 
       break; 
      } 
      baseProvider.SetValue(target, value); 
     } 

     #endregion 
    } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization); 
     if (property.PropertyType == typeof(string)) 
     { 
      property.ValueProvider = new StringRemappingValueProvider(property.ValueProvider, map, reverseMap); 
     } 
     return property; 
    } 
} 

然後使用它像:

public class User 
{ 
    public string user { get; set; } 

    public string name { get; set; } 

    public string dni { get; set; } 
} 

public class TestClass 
{ 
    public static void Test() 
    { 
     var settings = new JsonSerializerSettings { ContractResolver = new StringRemappingContractResolver() }; 

     var user = new User { user = "usertest", name = "nametest", dni = null }; 
     var json = JsonConvert.SerializeObject(user, settings); 
     Debug.WriteLine(json); // Prints {"user":"usertest","name":"nametest","dni":"-"} 
     Debug.Assert(JToken.DeepEquals(JToken.Parse(json), JToken.Parse(@"{'user':'usertest','name':'nametest','dni':'-'}"))); // No assert 
     var userBack = JsonConvert.DeserializeObject<User>(json, settings); 
     Debug.Assert(user.dni == userBack.dni && user.name == userBack.name && user.user == userBack.user); // No assert 
    } 
} 
0

您可以通過處理這定製IContractResolver。解析器可以將IValueProvider應用於每個字符串屬性,然後該字符串屬性將處理空值轉換爲-(如果反序列化相同的JSON,則返回)。

下面是你需要的解析器代碼:

public class NullStringReplacementResolver : DefaultContractResolver 
{ 
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> props = base.CreateProperties(type, memberSerialization); 

     // Attach a NullStringReplacementProvider instance to each string property 
     foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string))) 
     { 
      PropertyInfo pi = type.GetProperty(prop.UnderlyingName); 
      if (pi != null) 
      { 
       prop.ValueProvider = new NullStringReplacementProvider(pi); 
      } 
     } 

     return props; 
    } 

    protected class NullStringReplacementProvider : IValueProvider 
    { 
     PropertyInfo targetProperty; 

     public NullStringReplacementProvider(PropertyInfo targetProperty) 
     { 
      this.targetProperty = targetProperty; 
     } 

     // GetValue is called by Json.Net during serialization. 
     // The target parameter has the object from which to read the string; 
     // the return value is the string that gets written to the JSON 
     public object GetValue(object target) 
     { 
      // if the value of the target property is null, replace it with "-" 
      string s = (string)targetProperty.GetValue(target); 
      return (s == null ? "-" : s); 
     } 

     // SetValue gets called by Json.Net during deserialization. 
     // The value parameter has the original value read from the JSON; 
     // target is the object on which to set the value. 
     public void SetValue(object target, object value) 
     { 
      // if the value in the JSON is "-" replace it with null 
      string s = (string)value; 
      targetProperty.SetValue(target, s == "-" ? null : s); 
     } 
    } 
} 

要使用自定義解析器,你需要將它添加到被序列化和反序列化過程中使用的JsonSerializerSettings。如果您使用的ASP.NET Web API,你可以通過添加以下到Application_Start方法Global.asax.cs

var config = GlobalConfiguration.Configuration; 
var settings = config.Formatters.JsonFormatter.SerializerSettings; 
settings.ContractResolver = new NullStringReplacementResolver(); 

小提琴:https://dotnetfiddle.net/FVA3p8