Swagger-codegen: [csharp] Mustache templates do not distinguish generated and native parent classes

Created on 16 Feb 2018  路  6Comments  路  Source: swagger-api/swagger-codegen

Description

The mustache templates do not distinguish generated and native parent classes resulting in invalid code. For example, the override modifier is set in the modelGeneric.mustach template for the ToJson method if a non-array parent exists. But the parent can be a dictionary as well (see Swagger declaration below).

public {{#parent}}{{^isArrayModel}}override {{/isArrayModel}}{{/parent}}{{^parent}}{{#discriminator}}virtual {{/discriminator}}{{/parent}}string ToJson()

Same for the validate method:

{{#parent}} {{^isArrayModel}} foreach(var x in BaseValidate(validationContext)) yield return x; {{/isArrayModel}} {{/parent}}

BaseValidate does not exist in the dictionary class.

Swagger-codegen version

Version: 2.3.0
Is it a regression? Yes, works well with version 2.3.0-20170713.173236-24.

Swagger declaration file content or url
"KeyValues": {
  "type": "object",
    "additionalProperties": {
      "type": "string"
    }
}

Generates:
public partial class KeyValues : Dictionary<String, string>, IEquatable<KeyValues>, IValidatableObject

Command line used for generation

java -jar .\swagger-codegen-cli-2.3.0.jar generate -l csharp -i .\swagger.json -c .\config.json -o .\output\ -t .\templates\ --ignore-file-override .swagger-codegen-ignore

Steps to reproduce
  1. Create Swagger declaration with the definition mentioned above
  2. Create the code java -jar .\swagger-codegen-cli-2.3.0.jar generate -l csharp -i .\swagger.json
  3. Try to build the generated code. You will get an compiler error CS0115:
    'KeyValues.ToJson()' : no suitable method found to override
Suggest a fix/enhancement

If there would be a template variable like isArrayModel but for dictionaries or native parent classes in general, we could adjust the existing templates easily.

For example like this:
{{#parent}} {{^isArrayModel}} {{^isDictionary}} foreach(var x in BaseValidate(validationContext)) yield return x; {{/isDictionary}} {{/isArrayModel}} {{/parent}}

Most helpful comment

I get an error similar to this on swagger codegen v3 cli.
The name 'BaseValidate' does not exist in the current context

My OpenAPI spec is OpenAPI v 3.0.0. I don't use any additionalProperties, but I do have a few anyOf, allOf's. It appears that this ValidationContext function only shows up where my OpenAPI spec used anyOf.
I am using swagger cli 3.0.18 from here: https://mvnrepository.com/artifact/io.swagger.codegen.v3/swagger-codegen-cli/3.0.18

All 6 comments

Could anyone please clarify if there is a known fix for this issue? thank you.

@wickedw You can use the csharp-dotnet2 client code generator. Although it does not respect request content-types, the created code is easy to fix.

I get an error similar to this on swagger codegen v3 cli.
The name 'BaseValidate' does not exist in the current context

My OpenAPI spec is OpenAPI v 3.0.0. I don't use any additionalProperties, but I do have a few anyOf, allOf's. It appears that this ValidationContext function only shows up where my OpenAPI spec used anyOf.
I am using swagger cli 3.0.18 from here: https://mvnrepository.com/artifact/io.swagger.codegen.v3/swagger-codegen-cli/3.0.18

I get an error similar to this on swagger codegen v3 cli.
The name 'BaseValidate' does not exist in the current context

My OpenAPI spec is OpenAPI v 3.0.0. I don't use any additionalProperties, but I do have a few anyOf, allOf's. It appears that this ValidationContext function only shows up where my OpenAPI spec used anyOf.
I am using swagger cli 3.0.18 from here: https://mvnrepository.com/artifact/io.swagger.codegen.v3/swagger-codegen-cli/3.0.18

Same problem

I've thought that the solution would be to edit mustache template file to change BaseValidate to base.Validate
However the problem is that Validate method is not virtual and is not protected.

A derived class can't get access to the base Validate method unfortunately
The base IValidatableObject.Validate method can't be made protected also because of implicit interface implementation

It is possible to add a new BaseValidate method to the every model class being generated (not sure is there an option to check are there derived classes) like below:

protected IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> BaseValidate(ValidationContext validationContext)
{
    return ((IValidatableObject)this).Validate(validationContext);
}

However I do not think that implicit IValidatableObject interface implementation should be used.
So another option is to make Validate method public and virtual:
base

public virtual IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> Validate(ValidationContext validationContext)
{
    yield break;
}

derived

public override IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> Validate(ValidationContext validationContext)
{
    foreach(var x in base.Validate(validationContext)) yield return x;
    yield break;
}

What do you think? Which one is better ?

I've solved it right now by creating partial class with BaseValidate method implemented in the .cs file outside of auto generated Models folder.
I do not like it since it requires new files to be created manually for the new Models inheritance.

Regards

Was this page helpful?
0 / 5 - 0 ratings