Environment: .NET 6 WebAPI app
I have two classes, base an derived, that both can be used to serialize the output of a certain method as JSON and send it to client. They look like this:
public class Base
{
public int? Prop1 { get; set; }
public string? Prop2 { get; set; }
public long? Prop3 { get; set; }
...
}
public class Derived: Base
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public new int? Prop1 { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public new string? Prop2 { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public new long? Prop3 { get; set; }
...
}
and a generic model class that has a collection of Base objects:
public class Model
{
public List<Base>? Properties { get; set; }
...
}
I would like to always serialize the keys of Base
objects inside the Properties
collection, but skip the keys where the values are null
if I'm serializing a collection of Derived
objects. Sample code of what I want to achieve:
var baseModel = new Model{ Properties = new List<Base>{ new Base { Prop1 = 1 } } };
var serialized = JsonSerializer.Serialize(baseModel);
// This returns '{ "properties": { "Prop1": 1, "Prop2": null, "Prop3": null }}'
var derivedModel = new Model { Properties = new List<Derived>{ new Derived { Prop1 = 1 }}};
// This doesn't compile because of type mismatch
var derivedModel2 = new Model { Properties = new List<Base>{ (Base)new Derived { Prop1 = 1 }}};
// This works, but also returns '{ "properties": { "Prop1": 1, "Prop2": null, "Prop3": null }}'
// I need to get '{ "properties": { "Prop1": 1 } }' here
Any advice on where to look?
UPD: I've considered a generic class use, but my model is currently used in the following manner (simplified):
public class BusinessLogic: IBusinessLogic
{
... // Constructor with DI etc.
public async Task<Model> GetStuff(...)
{
...
var model = GetModelInternal(...);
...
return model;
}
}
public interface IBusinessLogic
{
...
public Task<Model> GetStuff(...);
...
}
public class MyController: ApiController
{
protected readonly IBusinessLogic _bl;
public MyController(..., IBusinessLogic bl)
{
_bl = bl;
}
[HttpGet]
public async Task<IActionResult> GetStuff(bool baseOrDerived, ...)
{
var model = await _bl.GetModel(baseOrDerived, ...);
return Json(model);
}
}
The type of the return objects (Base or Derived) needs to depend upon the input parameter baseOrDerived
that I get from the API client. This means that in order to use a generic I would need to pass the type parameter all the way through the controller. Moreover, I will have to introduce the same parameter to the IBusinessLogic/BusinessLogic
pair and instead of simply getting IBusinessLogic
instance from the DI, I would have to get a ServiceProvider
instance there, create a scope inside the action and construct templated instance of IBusinessLogic
dynamically. Given that this is NOT the only class I want this behavior from, this seems a real overkill to me.