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

Generating C# DTOs with custom generic class #1139

Closed
mronnblom opened this issue Jan 12, 2018 · 13 comments
Closed

Generating C# DTOs with custom generic class #1139

mronnblom opened this issue Jan 12, 2018 · 13 comments

Comments

@mronnblom
Copy link

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!

@RicoSuter
Copy link
Owner

Swagger/Open API and JSON Schema do not support generics (also see RicoSuter/NJsonSchema#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)

@mronnblom
Copy link
Author

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!

@mguoth
Copy link

mguoth commented Apr 10, 2019

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.

@RicoSuter
Copy link
Owner

See RicoSuter/NJsonSchema#23

@strangegt
Copy link

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

public class OneTimeAmountError: Error<OneTimeAmountErrorType>{
}

@Rynaret
Copy link
Contributor

Rynaret commented Jun 14, 2020

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

@Trapulo
Copy link

Trapulo commented Apr 9, 2021

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.

I also have this kind a problem with a Blazor project, and I'd like a way to create object as original generic types..

@fgilde
Copy link

fgilde commented Oct 10, 2021

I#ve created a tool for this problem. Its called makeGenericAgain and can be found here https://www.nuget.org/packages/MakeGenericAgain/ also source is available here https://github.com/fgilde/MakeGenericAgain

@emorell96
Copy link

@fgilde thank you so much for that tool! It's saving me a ton of time.

@fgilde
Copy link

fgilde commented Aug 1, 2022

Thank you very much. That makes me happy

@EtherZa
Copy link

EtherZa commented Aug 15, 2022

It's a little more effort, but generic classes can be remapped back to the original by:

  1. Specifying the NSwag generated class name as an alias in the "Additional Namespaces Usages" field ie. ErrorOfString = Error<string>
  2. Adding the NSwag generated class name to the "DTO Classes > Excluded Type Names" field ie. ErrorOfString

@vgb1993
Copy link

vgb1993 commented Nov 25, 2022

Could you share a example file please? That would be mind blowing

Do you guys recommend using this aproaches?

Do you know of any OpenAPI alternative that has generics support build in?

I would primarily need C# client generation, but also other languages for 3rd parties

Any thoughts?

Cheers

@JohnGalt1717
Copy link

PS: Generics are now supported by OpenAPI 3.1. So the statement at the top of this issue is no longer valid and this can be supported.

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