NSwag Enum generation starts from 0
Asked Answered
C

1

5

I have an Enum declared on a API like this :

 public enum Currencies
    {
        RON = 1,
        USD,
        EUR,
        GBP,
        CHF,
        PLN,
        CAD,
        HUF,
        NOK,
        SEK
    }

but when I use NSwag to generate a HttpClient, it starts from 0 and I obtain this:

public enum Currencies
    {

        [System.Runtime.Serialization.EnumMember(Value = @"RON")]
        RON = 0,

        [System.Runtime.Serialization.EnumMember(Value = @"USD")]
        USD = 1,

        [System.Runtime.Serialization.EnumMember(Value = @"EUR")]
        EUR = 2,

        [System.Runtime.Serialization.EnumMember(Value = @"GBP")]
        GBP = 3,

        [System.Runtime.Serialization.EnumMember(Value = @"CHF")]
        CHF = 4,

        [System.Runtime.Serialization.EnumMember(Value = @"PLN")]
        PLN = 5,

        [System.Runtime.Serialization.EnumMember(Value = @"CAD")]
        CAD = 6,

        [System.Runtime.Serialization.EnumMember(Value = @"HUF")]
        HUF = 7,

        [System.Runtime.Serialization.EnumMember(Value = @"NOK")]
        NOK = 8,

        [System.Runtime.Serialization.EnumMember(Value = @"SEK")]
        SEK = 9,

    }

the generated one starts from 0, while the initial one stars from 1. This leads to validation problems when I try to call the api. how can I map this ?

Cabdriver answered 26/1, 2022 at 18:5 Comment(1)
Did you get the solution for this. I am also facing the same problem :(Expatiate
K
7

Some solutions can be found in Stackoverflow, but I had struggle with them and will like to resume how to pass from what you have here to the solution. What is really important, it's to remove this code you certainly have:

        services.AddMvc().AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
        });

Or may be the following line in your swagger config

c.DescribeAllEnumsAsStrings()

When you do that, your generated code will look like that

public enum Currencies
{

    _1 = 1,

    _2 = 2,

    _3 = 3,

    _4 = 4,

    _5 = 5,

    _6 = 6,

    _7 = 7,

    _8 = 8,

    _9 = 9
}

Now your values are correct, the issue is about the name. So you can use the solution describe here : https://mcmap.net/q/871309/-swagger-c-enum-generation-underlying-int-values-do-not-match-the-original-enum and implement the NSwagEnumExtensionSchemaFilter and the NSwagEnumOpenApiExtension whitch add the "x-enumNames" schema details.

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

/// <summary>
/// Adds extra schema details for an enum in the swagger.json i.e. x-enumNames (used by NSwag to generate Enums for C# client)
/// https://github.com/RicoSuter/NSwag/issues/1234
/// </summary>
public class NSwagEnumExtensionSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (schema is null)
            throw new ArgumentNullException(nameof(schema));

        if (context is null)
            throw new ArgumentNullException(nameof(context));

        if (context.Type.IsEnum)
            schema.Extensions.Add("x-enumNames", new NSwagEnumOpenApiExtension(context));
    }
}

using System.Text.Json;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
using Swashbuckle.AspNetCore.SwaggerGen;

public class NSwagEnumOpenApiExtension : IOpenApiExtension
{
    private readonly SchemaFilterContext _context;
    public NSwagEnumOpenApiExtension(SchemaFilterContext context)
    {
        _context = context;
    }

    public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
    {
        string[] enums = Enum.GetNames(_context.Type);
        JsonSerializerOptions options = new() { WriteIndented = true };
        string value = JsonSerializer.Serialize(enums, options);
        writer.WriteRaw(value);
    }
}

services.AddSwaggerGen(c =>
{
    ...
    c.SchemaFilter<NSwagEnumExtensionSchemaFilter>();
});

Now your generated code will look like:

    public enum Currencies
    {
        [System.Runtime.Serialization.EnumMember(Value = @"RON")]
        RON = 1,

        [System.Runtime.Serialization.EnumMember(Value = @"USD")]
        USD = 2,

        [System.Runtime.Serialization.EnumMember(Value = @"EUR")]
        EUR = 3,

        [System.Runtime.Serialization.EnumMember(Value = @"GBP")]
        GBP = 4,

        [System.Runtime.Serialization.EnumMember(Value = @"CHF")]
        CHF = 5,

        [System.Runtime.Serialization.EnumMember(Value = @"PLN")]
        PLN = 6,

        [System.Runtime.Serialization.EnumMember(Value = @"CAD")]
        CAD = 7,

        [System.Runtime.Serialization.EnumMember(Value = @"HUF")]
        HUF = 8,

        [System.Runtime.Serialization.EnumMember(Value = @"NOK")]
        NOK = 9,

        [System.Runtime.Serialization.EnumMember(Value = @"SEK")]
        SEK = 10
  }

You can also add the EnumDocumentFilter if you want your swagger totally clean

Kirman answered 27/9, 2022 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.