3

I've recently started using ASP.NET Boilerplate as a starting point for a project I'm working on - Asp.NET Core Web Api + Angular, and I'm having trouble finding some information regarding something that seems to me like a common use issue. I'll try to explain what I mean the best I can.

What I want to do is to have an API endpoint that takes a parameter that needs to be restricted to a specific set of values - so, I wanted to use Enum for this purpose.

This all works nice as far as parameter validation goes, but I'm confused about how to make this work well with swagger and shared proxy generated services for fontend by Nswag.

Enum parameter is displayed as integer in the documentation parameter example, so it's not clear just by looking at the swagger documentation what is the set of available values, because int values have no meaning to the user that is looking at the documentation.

Lets use an example like this, user input used in one of app service methods:

Service method:

public async Task DoSomething(SomethingInput input)
{
    //some code handling user input
}

Input DTO:

public class SomethingInput : EntityDto<string>
{
    [EnumDataType(typeof(SomethingEnum))]
    public SomethingEnum Something { get; set; }

    public int SomeOtherData { get; set; }
}

Enum:

public enum SomethingEnum
{
    Option1,
    Option2,
    Option3
}

In this case, available values for SomethingEnum in SomethingInput will be shown as 0, 1, 3, instead of "Option1", "Option2", "Option2".

I tried using DescribeAllEnumsAsStrings for swagger generation options which helps with the documentation, but it creates an issue in the Angular project functionality - to be specific, changing tenant fails because of the way enums are generated using DescribeAllEnumsAsStrings by Nswag tool - it expects values to be integers, rather than strings.

export enum IsTenantAvailableOutputState {
    Available = <any>"Available", 
    InActive = <any>"InActive", 
    NotFound = <any>"NotFound", 
}

Response value returned by API is numeric, and this code doesn't know how to parse the value correctly anymore because enum no longer has integer values:

export class AppTenantAvailabilityState {
    static Available: number = IsTenantAvailableOutputState._1;
    static InActive: number = IsTenantAvailableOutputState._2;
    static NotFound: number = IsTenantAvailableOutputState._3;
}

The question here is, what is the best practice for having these kind of restrained parameters in routes or DTO objects used as user inputs, so that they are correctly displayed in swagger doc, and do not break down anything in angular project when regenerating shared proxies with Nswag tool?

spico
  • 31
  • 1

2 Answers2

0

my english is not very good but I will try to be clear.

I Had the same problem someday I have a Enum for gender and I Wanted to display Male and Female instead of 0 and 1 what is NSwag generates, to solve this In Angular template I made a Array in a static class that is like a copy of backend enum, and with this was able to load a Select.

Examples here

Enum in backend

public enum Sexo
{
    [Description("Masculino")]
    M,
    [Description("Fenemino")]
    F
}

Enum in angular after Nswag generates it.

export enum EstudianteDtoSexo {
_0 = 0, 
_1 = 1, 

}

The array in angular(That was the way for me to solve the problem)

export class SexoArray {
static Sexo =  [
    { value: 0, name: 'Masculino' },
    { value: 1, name: 'Femenino'}
];

Then I fill a ng-select with the elements of SexoArray bind it like this

                                    <div [ngClass]="(nombres.invalid && nombres.touched)?' form-group mb-4 has-error ':' form-group mb-4'">
                                    <label class="col-form-label">{{l("Sexo")}}<span class="text-danger"> *</span> </label>                            
                                    <ng-select 
                                        [(ngModel)]="estudiante.sexo" 
                                        name= "sexoSelect" 
                                        #sexoModel = "ngModel" 
                                        required>
                                        <ng-option *ngFor="let sex of sexo" [value]="sex.value">{{sex.name}}</ng-option>
                                    </ng-select>
                                    <app-input-validation [input]="sexoModel"></app-input-validation>
                                </div>

In this example estudiante.sexo is of type EstudianteDtoSexo

I Hope this could help you.

José Polanco
  • 123
  • 12
  • Unfortunately, adding description to enum values still doesn't display them correctly in the swagger documentation, and changes nothing tor the Nswag tool as far as generating enums in shared proxy services. Enums are still reflected as integers. – spico Dec 19 '18 at 07:39
  • I managed to resolve this issue for frontend by creating a custom SchemaFilter and applying this in AddSwaggerGen options, that added missing "x-enumNames" in swagger json needed for nswag tool to reflect enums in shared service proxies correctly. This did not help with displaying parameter descriptions correctly in swagger UI. – spico Dec 19 '18 at 07:53
0

I believe that instead of DescribeAllEnumsAsStrings() you need to add the StringEnumConverter to the SerializerSettings. In other words in ConfigureServices() in Startup.cs you should have something like this:

services
    .AddMvc(options => options.Filters.Add(new CorsAuthorizationFilterFactory(_defaultCorsPolicyName)))
    .AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));
Lee Richardson
  • 6,275
  • 4
  • 34
  • 55