How to manually trigger JsonSerialization Error

Viewed 267

I have an application where in the startup, I register NewtonSoft with error logging on serialization. When I check my application log, I can see there are error logs but I am having trouble pin pointing or recreating the error.

The error: Failed during serialization: MoveNextAction.Method.ReturnTypeCustomAttributes

Startup.cs

.AddControllersAsServices().AddNewtonsoftJson(options =>
{
    options.UseMemberCasing();
    options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
    options.AllowInputFormatterExceptionMessages = true;
    options.SerializerSettings.Formatting = Formatting.None;
    options.SerializerSettings.ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = null
    };
    options.SerializerSettings.Error = (sender, args) =>
    {
        _logger.LogError($"Failed during serialization: {args.ErrorContext.Path}", args.ErrorContext.Error);
        args.ErrorContext.Handled = true;
    };
})

I did a search in my application for serial

  • A couple classes have the [Serializable] attribute

I also use DeserializeObject

JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonValue); 

I tried and set jsonValue to null but unfortunately that did not trigger SerializerSettings.Error.

Any tips or suggestions on generating a SerializerSettings error or debugging would be greatly appreciated.

2 Answers

You can do this by passing an invalid JSON request body compared with the model class specified in the controller arguments.

Define a model class with an int field, then send an HTTP request where there is a string value in the JSON for that field.

This would come through to the controller as the default value, and in your case the Error handler should be executed as well.

Here is a working example:

public class HomeController : Controller
{
    public class MyRequest
    {
        public int MyField { get; set; }
    }

    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    [HttpPost]
    public IActionResult Test([FromBody] MyRequest myRequest)
    {
        return Ok();
    }
}

If you POST to /Home/Test the value

{
    "MyField": "test"
}

then your error handler will be invoked, and the value of args.ErrorContext.Path will be MyField

Although, the value of args.ErrorContext.Error will be Message = "Could not convert string to integer: test. Path 'MyField', line 2, position 18." I think I would need a much deeper understanding of your code to reproduce the error exactly, but I hope this helps.

When you add .AddControllersAsServices().AddNewtonsoftJson... it just triggers during input and output of your actions (actually in model binding and return action result).

So if you want trigger json serialize error in all your project you must set JsonSerializerSettings explicitly in your startup like this:

var defaultJsonConvertSetting = new JsonSerializerSettings
            {
                Formatting = Formatting.None,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                ContractResolver = new DefaultContractResolver {NamingStrategy = null},
               
                Error = (sender, args) =>
                {
                    Console.WriteLine($"**********************Failed during serialization: {args.ErrorContext.Path}");
                    args.ErrorContext.Handled = true;
                }
                // other settings
            };

            JsonConvert.DefaultSettings = () => defaultJsonConvertSetting;

                .AddControllersAsServices().AddNewtonsoftJson(options =>
            {
                options.UseMemberCasing();
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                options.AllowInputFormatterExceptionMessages = true;
                options.SerializerSettings.Formatting = Formatting.None;
                options.SerializerSettings.ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = null
                };
                options.SerializerSettings.Error = (sender, args) =>
                {
                    _logger.LogError($"Failed during serialization: {args.ErrorContext.Path}", args.ErrorContext.Error);
                    args.ErrorContext.Handled = true;
                };
            });
Related