Nswag: Generating C# DTOs with custom generic class

Created on 12 Jan 2018  路  6Comments  路  Source: RicoSuter/NSwag

I have a C# WebApi that exposes a class and enum like this:

public class Error<T>
{
    [Required]
    public T Code { get; set; }

    public string Message { get; set; }
}

public enum OneTimeAmountErrorType
{
    Unspecified = 0,
    AccountNotFound,
    InsufficientFunds
}

The error code can be a string or one of several enum types.

The generated Swagger (_not_ done with NSwag) looks like below. Only relevant parts and one of the enums included.

"Error[String]": {
    "required": ["code"],
    "type": "object",
    "properties": {
        "code": {
            "type": "string"
        },
        "message": {
            "type": "string"
        }
    }
}

"Error[OneTimeAmountErrorType]": {
    "required": ["code"],
    "type": "object",
    "properties": {
        "code": {
            "enum": ["Unspecified", "AccountNotFound", "InsufficientFunds"],
            "type": "string"
        },
        "message": {
            "type": "string"
        }
    }
}

Is there anything I can do, either with the Swagger generation, or with the NSwag client generation, to get a generic DTO like the original one? Using NSwagStudio 11.12.16.0, I get the following output (some stuff removed for brevity):

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.10.19.0 (Newtonsoft.Json v9.0.0.0)")]
public partial class ErrorOfString 
{
    [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)]
    [System.ComponentModel.DataAnnotations.Required]
    public string Code { get; set; }

    [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public string Message { get; set; }
}

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.10.19.0 (Newtonsoft.Json v9.0.0.0)")]
public partial class ErrorOfOneTimeAmountErrorType 
{
    [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)]
    [System.ComponentModel.DataAnnotations.Required]
    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public ErrorOfOneTimeAmountErrorTypeCode Code { get; set; }

    [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public string Message { get; set; }
}

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.10.19.0 (Newtonsoft.Json v9.0.0.0)")]
public enum ErrorOfOneTimeAmountErrorTypeCode
{
    [System.Runtime.Serialization.EnumMember(Value = "Unspecified")]
    Unspecified = 0,

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

    [System.Runtime.Serialization.EnumMember(Value = "InsufficientFunds")]
    InsufficientFunds = 2,
}

Having an enum named "ErrorOfOneTimeAmountErrorTypeCode" is not what I call intuitive. :)

If it is impossible to generate a Error<T>, an acceptable solution for me would be if I could get more control of the generated names. I.e. the enum above should be named as the original enum (I am aware that that isn't present in the Swagger though..).

Grateful for any help!

question

Most helpful comment

I wrote an article to show one of the possible solutions
https://medium.com/@rynaret/nswag-csharp-client-with-generics-support-6ad6a09f81d6

All 6 comments

Swagger/Open API and JSON Schema do not support generics (also see https://github.com/RSuter/NJsonSchema/issues/23).

I think there are two options:

  1. You can provide a custom ITypeNameGenerator via the NSwag settings and change how the class names are generated. For this however, you need to implement an own command line tool, because this generator can only be changed when using NSwag in code (i.e. as library).
  2. Transform the swagger spec before generating code: This is the simplest solution; just transform the spec (e.g. replace "Error[String]" with "Error" and "Error[OneTimeAmountErrorType]" with "EnumError"). You can use NSwag for that (sample: https://github.com/Picturepark/Picturepark.SDK.Playground/tree/master/src/AutoRestTransformer)

Ah, I see! Well I am in full control of the service, so it is probably best to just remove generics from the WebApi DTOs.

Thanks!

I have exactly the same problem. Maybe Swagger/OpenAPI doesn't support generic.

But, suppose that you already have following type names in swagger.json (Generated from Error<T> class):

"Error[String]"
"Error[OneTimeAmountErrorType]"

Currently, during NSwag code generation, type names above are converted into:

ErrorOfString
ErrorOfOneTimeAmountErrorType

Why is not possible to convert it into following type names? (e.g. by enabling some setting in configuration ".nswag" file):

Error<String>
Error<OneTimeAmountErrorType>

Generation of generic Error<T> Dto would be maybe a problem from these 2 types, but in my scenario (and possibly many others) the Dto's are shared with server, so there is no need to generate them on Client.

Many thanks for answer.

you can also define a wrap class, and use it instead of generic

public class OneTimeAmountError: Error<OneTimeAmountErrorType>{
}

I wrote an article to show one of the possible solutions
https://medium.com/@rynaret/nswag-csharp-client-with-generics-support-6ad6a09f81d6

Was this page helpful?
0 / 5 - 0 ratings