在我的Web api项目中,现在我正在跳过空值。因此,返回json忽略空值并打印属性。
在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 :(得分:1)
您可以使用自定义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();
答案 1 :(得分: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
}
}
答案 2 :(得分:-1)
您可以在globals.asax中注册转换器。你会添加这样的东西:
config.Formatters.JsonFormatter.SerializerSettings.Converters.add(new NullHandlerConverter());
其中,NullHandlerConverter是您需要编写的自定义转换器。
修改:Brian是对的。转换器无法使用,因为无法在{{::name}}
值上调用它们。