NSwag
NSwag copied to clipboard
Feature request: possibility to replace the JsonStringEnumConverter for System.Text.Json
It would be nice to have a commandline option for nswag that enables replacement of the annotation
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
.
As it stands, the JsonStringEnumConverter
has some shortcomings, which are alleviated by the open source package Macross.Json.Extensions. See: https://github.com/Macross-Software/core/blob/develop/ClassLibraries/Macross.Json.Extensions/README.md
In order to get the same effect, we now perform a replacement via powershell on the generated files:
((Get-Content -Path $filePath -Raw) -replace 'JsonStringEnumConverter', 'JsonStringEnumMemberConverter') | Set-Content -Path $filePath
I would second a request to edit the templated logic for enums when using
"jsonLibrary": "SystemTextJson",
The attribute for the JsonConverter that is applied to enums takes precedence over any enum based converter that might be added via the UpdateJsonSerializerSettings extension point.
Current template formats an enum like this:
[System.Text.Json.Serialization.JsonPropertyName("ecoaCode")]
[System.ComponentModel.DataAnnotations.StringLength(1)]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
public ConsumerInfoVoEcoaCode? EcoaCode { get; set; } = default!;
As AroglDarthu points out, the current MS supplied JsonStringEnumConverter converter has some limitations. Most notably is the lack of support for NSwag enums generated like this. _05 is provided in the Json string, not the "05" as desired.
public enum AccountInfoVoAccountStatusCode
{
[System.Runtime.Serialization.EnumMember(Value = @"05")]
_05 = 0,
Suggested fix:
Just remove the attribute [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
from the template.
Then allow/direct the users to the existing extension point to define an enum converter of their choice.
partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings)
{
// AroglDarthu can define his use case like this.
settings.Converters.Add( new System.Text.Json.Serialization.JsonStringEnumMemberConverter(allowIntegerValues: false));
// I might like this instead
settings.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverterWithAttributeSupport());
// MS User can do this:
settings.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
// Allow any additional settings as well.
settings.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
}
Think it over. Ed
@eobeda I like your proposal. It could even be implemented without a breaking change by providing a command-line option to suppress the attribute.
Are there any updates on this request? It would be nice to at least have a config flag to suppress the generation of System.Text.Json.Serialization.JsonConverterAttribute
on enum properties so that a custom converter defined w/ the config flag JsonConverters
can be utilized for enum properties. Or alternatively have a config value to specify the converter type to be used in the generation of that attribute.
I was able to change the attribute using template overrides (https://github.com/RicoSuter/NSwag/wiki/Templates). It would still be nice to have it as a configurable option, as to remove the need for a template override; however, this is now a non-issue to all my intents, constructions and purposes.
We use powershell to kick off the client generation. As a workaround we just replaced the attribute with what we needed from the same powershell script. Ugly hack, but it works. A built-in option, like @eobeda 's proposal, would be extremely useful.
Thanks for the suggestion!
I was replacing the line post generation via the csproj, but that caused the file to always be triggered by the build's up-to-date check (so building the containing multi-project solution would always build that project even when it contained no actual changes).
I could have just removed the generated file from the up-to-date check by using a csproj UpToDateCheckInput
item, but that was not feasible since I still want the build to be noticed as out-of-date when the file is regenerated.
I was able to change the attribute using template overrides (https://github.com/RicoSuter/NSwag/wiki/Templates). It would still be nice to have it as a configurable option, as to remove the need for a template override; however, this is now a non-issue to all my intents, constructions and purposes.
For those interested, here is the relevant lines to remove for what he's suggesting. You will need to sub in your own enum converter to the JsonSerializationSettings if you dont just want the enum numbers. https://github.com/RicoSuter/NJsonSchema/blob/94647c590b3c6cbc3d09569b027ee7cd77c20463/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid#LL83-L89C15
Any update on this, we need the same feature
Has this been fixed yet?
Also stuck here. I have no extension point to make it work.
Openapi spec:
Generated enum:
Generated class that uses the enum:
The serialized enum value is pascal-cased, e.g. AccountHolderKey
instead of accountHolderKey
, and the API call fails.
@rafaelkallis
If you are using an NSwag configuration file (e.g., nswag.json) for your build then you can add a template overrides directory from there.
{
...
"codeGenerators": {
...
"templateDirectory": "./TemplateOverrides"
}
}
And then just put the raw Class.liquid into that directory w/ any updates relevant per my post (https://github.com/RicoSuter/NSwag/issues/3846#issuecomment-1279779176) and @JustinGrote's post (https://github.com/RicoSuter/NSwag/issues/3846#issuecomment-1462659271).
Raw: https://raw.githubusercontent.com/RicoSuter/NJsonSchema/master/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid
If you are not using an NSwag configuration file, then it might be preferable for you to investigate how to incorporate that into your project. Or if that not feasible then there might be some other method for passing a configuration for the template overrides directory into whatever entry point you have for the NSwag library.