Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i ignore errors in json deserialization using [FromBody]?

I use asp net core 3.0 and I have problem:

Model:

public class Location
{
    public string Name { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

Method in controller

[HttpPost("api/somePost")]
public Task Test([FromBody] Location location)
{
    // Do somethimg
    return Task.CompletedTask;
}

Startup:

services.AddMvc().AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.Error = (sender, args) =>
            {
                args.ErrorContext.Handled = true;
            };
        });

I send json with Postman

postman request

and get null in location parameter in controller method!

error handler

and

controller method

How can ignore error of type converting and get default value (0) in "Longitude" property?

like image 431
Eugene Avatar asked Nov 15 '22 23:11

Eugene


1 Answers

It sounds like you need a custom converter (as also mentioned in the comments).

public class YourCustomConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(double));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return serializer.Deserialize<double>(reader);
        }
        catch
        {
            return 0d;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

Now you just decorate the properties you want this to be valid for with JsonConverter. For your example it would look like this:

public class Location
{
    public string Name { get; set; }

    [JsonConverter(typeof(YourCustomConverter))]
    public double Latitude { get; set; }

    [JsonConverter(typeof(YourCustomConverter))]
    public double Longitude { get; set; }
}

Now, if you send in invalid data, the deserializer will throw an exception, which is catched by the custom converter that returns 0 instead (or whatever value you want it to be).

UPDATE:

Disclaimer: This is untested!

You could probably make a generic converter to handle all cases:

public class YourCustomConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(T));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return serializer.Deserialize<T>(reader);
        }
        catch
        {
            return default(T);
        }
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

You could still use this as an attribute [JsonConverter(typeof(YourCustomConverter<double>)].

There's also an option to use a custom converter for all JSON serialization/deserialization using this code:

services.AddMvc().AddNewtonsoftJson(options =>
{
    // Configure a custom converter
    options.SerializerOptions.Converters.Add(new SomeOtherCustomJsonConverter());
});

However, this can't really be made generic so you would have to write your own handling of all your possible types.

like image 113
GTHvidsten Avatar answered May 19 '23 20:05

GTHvidsten