Json serializer NullValueHandling without using datamember attribute

In my Web api project, right now I'm skipping null values. therefore return json ignores null values ​​and prints the property.

In the Global.asax file:

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

However, I want to replace the null values ​​with "-". but I do not want to use the data element attribute for each property ...

[DefaultValue("-")]. 

I have more than 10 classes in my project ... so this is not the most elegant solution.

I want this to be a simple solution and applicable to any conversion, as well as null values ​​from Global.asax

Example.

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

    public string name { get; set; }

    public string dni { get; set; }
}

when all data exists, my return service

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

But when dni does not exist, answer that

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

So, I would like to answer as follows

{
  "user": "usertest",
  "name": "nametest",
  "dni": "-"
}
+1
source share
3 answers

. , , , " " "-", , , .

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

Fiddle: https://dotnetfiddle.net/FVA3p8

0

globals.asax. - :

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

, NullHandlerConverter - , .

: . , null.

-1

Source: https://habr.com/ru/post/1688302/


All Articles