0
votes

I have simple controller with custom model type Heading - without parameterless constructor and public setter.

I tried following code in asp.net mvc core 2.2 and 3.1.

Model class:

public class Heading
{
    public string Title { get; }
    public Heading(string title)
    {
        Title = title;
    }
}

API Controller:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpPost]
    public void Post([FromBody] Heading value)
    {
    }
}

With .net core 2.2, binding works perfectly. But for core 3.1, it throws error

System.NotSupportedException: Deserialization of reference types without parameterless constructor is not supported. Type 'WebApplication3.Controllers.Heading' at System.Text.Json.ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(Type invalidType)

Is this change in behaviour? Can it still be achieved?

3
I'm suprised a model without parameterless constructor was actually supported in .net core 2.2 . How did it even work ?Pac0

3 Answers

4
votes

In ASP.NET Core 2.2, it works just because of Newtonsoft.Json. In ASP.NET Core Version >= 3.0 it was replaced by System.Text.Json. Here is more about System.Text.Json, the new default ASP.NET Core JSON Serializer.

If you’d like to switch back to the previous default of using Newtonsoft.Json, do the following:

First Install the Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet package. Then in ConfigureServices() add a call to AddNewtonsoftJson() as follows:

public void ConfigureServices(IServiceCollection services)
{
     ...
     services.AddControllers()
          .AddNewtonsoftJson()
     ...
 }

For more details: ASP.NET Core 3.0 - New JSON serialization

1
votes

Although you can change the default serializer and return to the previous functionality Newtonsoft.Json as mentioned by @TanvirArjel, the ideal is to use the default serializer System.Text as it has better performance. You can check it here: How to migrate from Newtonsoft.Json to System.Text.Json The error is caused due to the fact that the Heading class does not have a constructor valid without arguments which should be defined as follows.

public class Heading {
    Heading(){
    }
    public string AttrOne {get; set;}
    public string AttrTwo {get; set;}
}
0
votes

From the docs:

Complex types

A complex type must have a public default constructor and public writable properties to bind. When model binding occurs, the class is instantiated using the public default constructor.

You will need to add a parameter-less constructor for binding to use that model.

The behavior may have worked for you before (2.2 and prior) if you were using NewtonsoftJson which may have allowed parameter-less constructor models. Since 3.0 .NET Core uses the newer System.Text.Json serializer by default.