I have model classes ClassA and ClassB.
These classes are returned as result from two controllers: XController and YController.
When returning these classes as result from YController, default serialization is to be used.
When returning these classes as result from XController, two properties of ClassA should be renamed (no change to the types or how the values are output) and one property of ClassB needs to be renamed (same as before). XController only has GET calls, so doesn't need to handle custom de-serialization. Using JsonPropertyName doesn't meet this requirement.
How can I do this?
I followed Using multiple JSON serialization settings in ASP.NET Core to add a custom SystemTextJsonOutputFormatter (called ExternalJsonOutputFormatter (for outputting JSON to be used by "external" clients)). However, I can't see where and how I can customize the names of specific properties. My guess is I have to override WriteAsync(...) method, but don't know what to do in there (e.g., how low-level do I have to go to achieve what I want?).
Even links to online examples could be handy (I couldn't find anything that would show me what I need).
I would highly prefer to stick to System.Text.Json.
As a placeholder I've implemented the following solution (since I needed a solution fast), though I'd prefer a better, more standardized way of doing this, so looking forward to the answers.
I already had a utility method that takes an
objectand converts it into an equivalentIDictionary<string, object?>:When returned as a result of an endpoint call, the serialization is exactly as expected (think about it: the simplest & most direct representation of JSON in C# is
IDictionary<string, object?>, possibly contained within anIList).I created an attribute
DictionaryPropertyNameAttribute(analogous toJsonPropertyNameAttribute) which can be used to supply custom names. The difference is, whileJsonPropertyNameAttribute, once set, will always be applied, I added aboolto myToDictionarycall to allow the method caller to turn on/off the renaming:The
useCustomNamesisfalseby default for backwards compatibility.This solution works, though, as mentioned previously, I'm open to other, better ideas.