Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REQ][C#] Support Case-Insensitive String Enums #20297

Open
ajrice6713 opened this issue Dec 11, 2024 · 0 comments
Open

[REQ][C#] Support Case-Insensitive String Enums #20297

ajrice6713 opened this issue Dec 11, 2024 · 0 comments

Comments

@ajrice6713
Copy link
Contributor

Is your feature request related to a problem? Please describe.

The Java client offers a useCaseInsensitiveEnums flag in the configuration to support case-insensitive string enums. It would be great if the C# SDK offered the same - it looks like this is requested for other generators in ##16634 and #17398

Describe the solution you'd like

A config option for allowing case-insensitive string enums. Our API sends a webhook that we have defined as an enum in our OpenAPI spec with the values in and out. When attempting to serialize to a model generated via the project - I get this error

Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to read parameter "List<MessageDeliveredCallback> callbackData" from the request body as JSON.
 ---> System.Text.Json.JsonException: The JSON value could not be converted to Bandwidth.Standard.Model.MessageDeliveredCallbackMessage. Path: $[0].message.direction | LineNumber: 22 | BytePositionInLine: 23.
   at System.Text.Json.ThrowHelper.ThrowJsonException(String message)
   at System.Text.Json.Serialization.Converters.EnumConverter`1.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.TryReadAsObject(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, Object& value)
   .....

This is the generated model definition

   [JsonConverter(typeof(StringEnumConverter))]
    public enum MessageDirectionEnum
    {
        /// <summary>
        /// Enum In for value: in
        /// </summary>
        [EnumMember(Value = "in")]
        In = 1,

        /// <summary>
        /// Enum Out for value: out
        /// </summary>
        [EnumMember(Value = "out")]
        Out = 2
    }

From what I can tell - dotnet doesnt have any built in support for this so we would need a custom CaseInsensitiveEnumConverter<T> class that looks something like

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public class CaseInsensitiveEnumConverter<T> : JsonConverter<T> where T : struct, Enum
{
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var value = reader.GetString();
        if (Enum.TryParse(value, ignoreCase: true, out T result))
        {
            return result;
        }
        throw new JsonException($"Invalid value '{value}' for enum {typeof(T).Name}");
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

to be used on the generated enum classes

using System.Text.Json.Serialization;

[JsonConverter(typeof(CaseInsensitiveEnumConverter<MessageDirectionEnum>))]
public enum MessageDirectionEnum

Looking through the codebase for the csharp generator, there is a lot of custom logic around the enums already with the zeroBasedEnums config option, so ideally we wouldn't want to break that

Describe alternatives you've considered

Clients can set an option to use caseInsensitive serialization - but it would be nice to have this built in

new JsonSerializerOptions
        {
            Converters = { new JsonStringEnumConverter() },
            PropertyNameCaseInsensitive = true
        });

With some guidance on how the config options dictate what is generated in the templates i could take a crack at implementing this - I have contributed to the templates previously - but not connected the build args to whats generated yet - so if there is any guidance or old PRs to look at, I'd be willing to take a crack at it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant