Search code examples
c#restasp.net-coreminimal-apis

Minimal API Results.Ok Not Returning Full Object


While working on a larger Minimal API project, Results.Ok() was not returning the full object. However, switching to Results.Text() returns the full object.

I've included the full listing of a simple application that I created to see if I can reproduce the behavior. The application includes two endpoints that are supposed to return the same object.

using Newtonsoft.Json;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

School school = new School();
school.SchoolName = "My Elementary School";
school.Students.Add(new Student() { FirstName = "Bill", LastName = "Smith", Grade = 4, StudentID = "123456" });
school.Students.Add(new Student() { FirstName = "Jane", LastName = "Doe", Grade = 5, StudentID = "54321" });

app.MapGet("/SchoolsV1", () =>
{
    return Results.Ok(school);
});

app.MapGet("/SchoolsV2", () =>
{
    string strValue = JsonConvert.SerializeObject(school, Formatting.Indented);
    return Results.Text(strValue, "application/json", null);
});

app.Run();


public class School
{
    public string SchoolName { get; set; }
    public List<Student> Students = new List<Student>();
}
public class Student
{
    public string StudentID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Grade { get; set; }
}

Using Postman I get the following results.

https://localhost:7000/SchoolsV1

{
    "schoolName": "My Elementary School"
}

Then

https://localhost:7000/SchoolsV2


{
    "Students": [
        {
            "StudentID": "123456",
            "FirstName": "Bill",
            "LastName": "Smith",
            "Grade": 4
        },
        {
            "StudentID": "54321",
            "FirstName": "Jane",
            "LastName": "Doe",
            "Grade": 5
        }
    ],
    "SchoolName": "My Elementary School"
}

Is this expected behavior? Is there something I'm missing when using Results.Ok()?


Solution

  • Results.Ok (which is actually not needed here, you can use just app.MapGet("/SchoolsV1", () => school) uses the default System.Text.Json serializer (more info about it can be found in the docs) which does not serialize fields by default. There are several options.

    Easiest one is to change School.Students to be a property:

    public class School
    {
        public string SchoolName { get; set; }
        public List<Student> Students { get; set; } = new List<Student>();
    }
    

    Or configure Microsoft.AspNetCore.Http.Json.JsonOptions:

    builder.Services.Configure<JsonOptions>(opts => opts.SerializerOptions.IncludeFields = true);
    var app = builder.Build();
    // ...