Consider the following minimal repro example using the default ASP.NET Core template:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Content-Type application/json, Body: true
app.MapGet("/True", () => Results.Json(true));
// Content-Type application/json, Body: "string"
app.MapGet("/String", () => Results.Json("string"));
// Content-Type application/json, Body: {"someProperty":"someValue"}
app.MapGet("/Object", () => Results.Json(new { SomeProperty = "someValue" }));
// expected: Content-Type application/json, Body: null
// actual: no Content-Type header, zero-length Body
app.MapGet("/Null", () => Results.Json(null));
app.Run();
As you can see, Results.Json
always yields a Content-Type of application/json
and a body containing the json-serialized version of the first argument, except in the case of null (which is annoying, because it means I need to treat this special case in my client differently as well).
I know that I can work around this by creating my own version of Results.Json
, but I’d like to understand why this happens. After all, the developers of the Results
class apparently went the extra mile to implement a special-case logic for null
, so they might have had a good reason for doing that (which I don’t understand yet). Unfortunately, the documentation has not been helpful.
Note:
- I know that I don’t need
Results.Json
for the first (/True
) and the third (/Object
) case. I do need it for the second case, because otherwise ASP.NET will return text (Content-Type text/plain) instead of a JSON string, which would mean yet another special case in my client. app.MapGet("/Null2", () => (object?)null);
does return the expected result (a JSON-encodednull
).
2
Answers
This can’t be done via
Results.Json
because it explicitly does nothing fornull
value – source code.You can return null as object:
Or explicitly serialize and return content:
As for why – I can only guess here – mine would be "perfromance", maybe there is a case in TechEmpower benchmarks which allows such return, so shortcutting makes sense =)
The only other way I could figure out how to get the null JSON value was using JsonElement: