Allow to specify type to serialize in SystemTextJsonOutputFormatter
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 276
Description
### Is there an existing issue for this?
- [X] I have searched the existing issues
### Is your feature request related to a problem? Please describe the problem.
I'm trying to specify what type the `SystemTextJsonOutputFormatter` should serialize, but it's not possible, because it goes out of its way to use the actual type of the value.
Let's consider code like this:
```csharp
class Parent {}
class Child : Parent {
public string Prop { get; set; }
}
[ApiController]
class Ctrl : ControllerBase {
[HttpGet]
public Parent Get1() {
return new Child();
}
[HttpGet]
public ActionResult Get2()
{
return new Child();
}
[HttpGet]
public IActionResult Get3() {
// getting desperate ...
var ok = Ok(new Child());
ok.DeclaredType = typeof(Parent);
return ok;
}
}
```
In all cases above, the value is serialized as `Child` and not `Parent`. In fact there seems to be no way to serialize it as `Parent`.
This is because of code in `SystemTextJsonOutputFormatter`
https://github.com/dotnet/aspnetcore/blob/f9ae0f5d30be2de3c0de61b5673bd8873231d70a/src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonOutputFormatter.cs#L73-L77
I understand the sentiment. As the comment says, you want to be compatible with NewtonsoftJson at least at the root level. But I think it goes too far and hope that there can be a way added to specify the type for serialization.
I think the comment: "context.ObjectType reflects the declared model type when specified" is inaccurate. In case of simple return type (`Parent Get() {}`), the `ObjectType` property is in fact set to the runtime type of the instance due to code in `OutputResultExecutor`:
https://github.com/dotnet/aspnetcore/blob/6d21cf11d65283fadbeb044b760c2f4dcf2c7010/src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs#L89-L94
### Describe the solution you'd like
I understand that there's slim chance you'll change the existing behavior, because it will be a breaking change. But anyway, I'd like the cases where `ObjectResult` specifies the `DeclaredType` to pass that type to the STJ serializer. That means that in the example code above, second and third cases should serialize the value as `Parent` and not `Child`.
### Additional context
I stumbled upon this problem when analyzing some code that directly returns EF entities out of MVC actions. The entity used virtual property for lazy loading support. The property was decorated with `JsonIgnore` attribute, but it didn't work.
The analysis showed that Mvc passes the EF-generated proxy type to STJ and STJ doesn't read inherited attributes (`GetCustomAttributes(..., inherit: false)`. The end result is that lazy loaded property was getting serialized while the intention was to ignore it.
Contributor guide
Assessment
This issue has not been assessed yet.