ASP.NET Core Pitfalls – Null Models in Post Requests

Sometimes, when AJAX posting to a controller, you may get a null model. Why?

Let’s exclude the obvious – you didn’t send a null payload. The most typical reason is, the serializer could not deserialize the payload into the target type, and it just silently sets it to null, but no exception is thrown. Take this example:

public class Data

{

    public string X { get; set; }

    public int Y { get; set; }

}

If you try to send something totally unrelated, such as this:

<script>

     function process() {
         $.ajax({
             url: '/Home/Process',
             headers: {
                 'Content-Type': 'application/json',
             },
             data: { 'foo': 'bar' },
             type: 'POST',
             success: function (data) {

             },
             complete: function () {
             },
             error: function (error) {
             }
         });
     }

</script>

It should come as no surprise that the content you send is unrelated to the model you are expecting in your action method, therefore there is a mismatch, but you may be surprised to get a null value instead of an exception.

The code responsible for binding the request to the .NET class is the input formatter that can be specified in the AddMvc extension method:

services.AddMvc(options =>

{
    options.InputFormatters.Clear();
    options.InputFormatters.Add(new MyInputFormatter());
}):

In ASP.NET Core 5, the only included one is SystemTextJsonInputFormatter, which uses the System.Text.Json API for parsing the request as JSON and deserializing it into a .NET class. You can add as much input formatters as you want, the first one that can process the request is used and all the others are discarded, so the order matters.