C# - Model is always getting its default values

714 views Asked by At

I have an ASP.Net Core 2.1 application.

Below is my DTO

public class Movie
{
  public int Id { get; set;}

  public bool IsSpecial {get; set;}

  public IEnumerable<Ticket> Tickets { get; set; }

    public Movie()
    {
        if(IsSpecial)
        {
            this.Tickets = new List<TicketSpecial>();
        }
        else
        {
            this.Tickets = new List<Ticket>();
        }
    }}}

Tickets (Base Class)

 public class Ticket
 {
   public int Id { get; set;}

   public string Name { get; set;}

   public decimal price { get; set;}
 } 

TicketsSpecial (Child/Derived Class)

 public class TicketsSpecial : Ticket
 {
    public string SpecialProp1 { get; set;}

    public string SpecialProp2 { get; set;}

 }

WebAPI Controller

public class MovieController : ControllerBase
{

  public IActionResult Post([FromBody]Movie movie)
  {
  }
}

Postman (HTTPPost Req payload Content-Type = application/json)

{
"IsSpecial": true,
"SpecialProp1": "Mumbai Test",
}

When I call the above API via Postman & debug at Movie ctor, it always catches the value of IsSpecial = false & all fields default value (ex. for string type null)

Thanks!

2

There are 2 answers

0
Fran On

Change "Isspecial" to "isSpecial", same with the other property.

Another problem is that you're checking "IsSpecial" in the constructor and at this time it should be false anyway.

0
Edward On

There are two issues in your current implementation. First, your request json is invalid for nested properties and json deserializer would not deserialize for you with TicketsSpecial.

Follow steps below for a workaround:

  1. Movie

    public class Movie
    {
            public int Id { get; set; }
    
            public bool IsSpecial { get; set; }
    
            public IEnumerable<Ticket> Tickets { get; set; }
    
    }
    
  2. MyJsonInputFormatter

    public class MyJsonInputFormatter : JsonInputFormatter
    {
            public MyJsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings, ArrayPool<char> charPool, ObjectPoolProvider objectPoolProvider, MvcOptions options, MvcJsonOptions jsonOptions) : base(logger, serializerSettings, charPool, objectPoolProvider, options, jsonOptions)
            {
    
            }
            public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
            {
            var result = await base.ReadRequestBodyAsync(context);
            if (result.Model is Movie movie && movie.IsSpecial)
            {
                    context.HttpContext.Request.Body.Position = 0;
                    string request = await new StreamReader(context.HttpContext.Request.Body).ReadToEndAsync();
                    var tickets = JObject.Parse(request)["Tickets"].ToObject<List<TicketSpecial>>();
                    movie.Tickets = tickets;
            }
            return result;
            }
    }
    
  3. Register MyJsonInputFormatter

    services.AddMvc(o =>
    {
            var serviceProvider = services.BuildServiceProvider();
            var customJsonInputFormatter = new MyJsonInputFormatter(
                            serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<MyJsonInputFormatter>(),
                            serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value.SerializerSettings,
                            serviceProvider.GetRequiredService<ArrayPool<char>>(),
                            serviceProvider.GetRequiredService<ObjectPoolProvider>(),
                            o,
                            serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value
                    );
    
            o.InputFormatters.Insert(0, customJsonInputFormatter);
    })
    
  4. Request

            {
                    "IsSpecial": true,
                    "Tickets":  [
                                    {"SpecialProp1": "Mumbai Test"}
                            ]
            }