question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AdditionalProperties JsonExtensionData repeated for subclasses in generated C# contracts

See original GitHub issue

Given:

{
  "x-generator": "NSwag v13.4.2.0 (NJsonSchema v10.1.11.0 (Newtonsoft.Json v12.0.0.0))",
  "openapi": "3.0.0",
  "info": {
    "title": "My Title",
    "version": "1.0.0"
  },
  "paths": {
    "/WeatherForecast": {
      "get": {
        "tags": [
          "WeatherForecast"
        ],
        "operationId": "GetCurrentWeatherForecast",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WeatherForecast"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/400",
            "description": ""
          },
          "401": {
            "$ref": "#/components/responses/401",
            "description": ""
          },
          "403": {
            "$ref": "#/components/responses/403",
            "description": ""
          },
          "404": {
            "$ref": "#/components/responses/404",
            "description": ""
          },
          "500": {
            "$ref": "#/components/responses/500",
            "description": ""
          },
          "503": {
            "$ref": "#/components/responses/503",
            "description": ""
          }
        }
      },
      "post": {
        "tags": [
          "WeatherForecast"
        ],
        "operationId": "UploadWeatherForecast",
        "requestBody": {
          "x-name": "request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WeatherForecast"
              }
            }
          },
          "required": true,
          "x-position": 1
        },
        "responses": {
          "200": {
            "description": ""
          },
          "400": {
            "$ref": "#/components/responses/400",
            "description": ""
          },
          "401": {
            "$ref": "#/components/responses/401",
            "description": ""
          },
          "403": {
            "$ref": "#/components/responses/403",
            "description": ""
          },
          "404": {
            "$ref": "#/components/responses/404",
            "description": ""
          },
          "500": {
            "$ref": "#/components/responses/500",
            "description": ""
          },
          "503": {
            "$ref": "#/components/responses/503",
            "description": ""
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "WeatherForecast": {
        "type": "object",
        "description": "Represents a weather forecast for the given date.",
        "properties": {
          "date": {
            "type": "string",
            "description": "The time of the forecast.",
            "format": "date-time"
          },
          "temperatureC": {
            "type": "integer",
            "description": "The temp in celsius.",
            "format": "int32"
          },
          "temperatureF": {
            "type": "integer",
            "description": "The temp.",
            "format": "int32"
          },
          "summary": {
            "type": "string",
            "description": "The description."
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        }
      },
      "ValidationProblemDetails": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProblemDetails"
          },
          {
            "type": "object",
            "properties": {
              "errors": {
                "type": "object",
                "nullable": true,
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        ]
      }
    },
    "responses": {
      "400": {
        "description": "Bad Request",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationProblemDetails"
            }
          },
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationProblemDetails"
            }
          }
        }
      },
      "401": {
        "description": "Unauthorized"
      },
      "403": {
        "description": "Forbidden"
      },
      "404": {
        "description": "Not Found",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          },
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "500": {
        "description": "Internal Server Error",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          },
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "503": {
        "description": "Service Unavailable",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          },
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      }
    },
    "parameters": {
      "AuthorizationHeaderParameter": {
        "name": "Authorization",
        "in": "header",
        "required": true,
        "description": "The HTTP Authorization request header contains the credentials to authenticate a user agent with a server (From MDN).",
        "schema": {
          "type": "string",
          "nullable": false
        }
      }
    }
  }
}
{
  "runtime": "NetCore31",
  "defaultVariables": null,
  "documentGenerator": {
    "aspNetCoreToOpenApi": {
      "project": "NSwagTestHarness.csproj",
      "msBuildProjectExtensionsPath": null,
      "configuration": "$(Configuration)",
      "targetFramework": null,
      "noBuild": true,
      "verbose": false,
      "workingDirectory": null,
      "requireParametersWithoutDefault": true,
      "apiGroupNames": null,
      "defaultPropertyNameHandling": "Default",
      "defaultReferenceTypeNullHandling": "Null",
      "defaultDictionaryValueReferenceTypeNullHandling": "NotNull",
      "defaultResponseReferenceTypeNullHandling": "NotNull",
      "defaultEnumHandling": "String",
      "flattenInheritanceHierarchy": false,
      "generateKnownTypes": true,
      "generateEnumMappingDescription": false,
      "generateXmlObjects": false,
      "generateAbstractProperties": false,
      "generateAbstractSchemas": true,
      "ignoreObsoleteProperties": false,
      "allowReferencesWithProperties": false,
      "excludedTypeNames": [],
      "serviceHost": null,
      "serviceBasePath": null,
      "serviceSchemes": [],
      "infoTitle": "Transaction Service",
      "infoDescription": null,
      "infoVersion": null,
      "documentTemplate": null,
      "documentProcessorTypes": [],
      "operationProcessorTypes": [],
      "typeNameGeneratorType": null,
      "schemaNameGeneratorType": null,
      "contractResolverType": null,
      "serializerSettingsType": null,
      "useDocumentProvider": true,
      "documentName": "v1",
      "aspNetCoreEnvironment": "Development",
      "createWebHostBuilderMethod": null,
      "startupType": "NSwagTestHarness.Startup",
      "allowNullableBodyParameters": false,
      "output": "gen/test-v1.json",
      "outputType": "OpenApi3",
      "assemblyPaths": [],
      "assemblyConfig": null,
      "referencePaths": [],
      "useNuGetCache": false
    }
  },
  "codeGenerators": {
    "openApiToCSharpClient": {
      "clientBaseClass": "ApiClientBase",
      "configurationClass": null,
      "generateClientClasses": true,
      "generateClientInterfaces": true,
      "injectHttpClient": true,
      "disposeHttpClient": false,
      "protectedMethods": [],
      "generateExceptionClasses": true,
      "exceptionClass": "TestClientException",
      "wrapDtoExceptions": true,
      "useHttpClientCreationMethod": false,
      "httpClientType": "System.Net.Http.HttpClient",
      "useHttpRequestMessageCreationMethod": true,
      "useBaseUrl": false,
      "generateBaseUrlProperty": false,
      "generateSyncMethods": false,
      "exposeJsonSerializerSettings": false,
      "clientClassAccessModifier": "public",
      "typeAccessModifier": "public",
      "generateContractsOutput": true,
      "contractsNamespace": "NSwagTestHarness.Client",
      "contractsOutputFilePath": "../NSwagTestHarness.Client/gen/Contracts.g.cs",
      "parameterDateTimeFormat": "o",
      "generateUpdateJsonSerializerSettingsMethod": true,
      "serializeTypeInformation": false,
      "queryNullValue": "",
      "className": "NSwagTestHarnessClient",
      "operationGenerationMode": "SingleClientFromOperationId",
      "additionalNamespaceUsages": [],
      "additionalContractNamespaceUsages": [],
      "generateOptionalParameters": true,
      "generateJsonMethods": false,
      "enforceFlagEnums": false,
      "parameterArrayType": "System.Collections.Generic.IEnumerable",
      "parameterDictionaryType": "System.Collections.Generic.IDictionary",
      "responseArrayType": "System.Collections.Generic.ICollection",
      "responseDictionaryType": "System.Collections.Generic.IDictionary",
      "wrapResponses": false,
      "wrapResponseMethods": [],
      "generateResponseClasses": false,
      "responseClass": "NSwagTestHarnessResponse",
      "namespace": "NSwagTestHarness.Client",
      "requiredPropertiesMustBeDefined": true,
      "dateType": "System.DateTime",
      "jsonConverters": null,
      "anyType": "object",
      "dateTimeType": "System.DateTime",
      "timeType": "System.TimeSpan",
      "timeSpanType": "System.TimeSpan",
      "arrayType": "System.Collections.Generic.ICollection",
      "arrayInstanceType": "System.Collections.Generic.List",
      "dictionaryType": "System.Collections.Generic.IDictionary",
      "dictionaryInstanceType": "System.Collections.Generic.Dictionary",
      "arrayBaseType": "System.Collections.Generic.List",
      "dictionaryBaseType": "System.Collections.Generic.Dictionary",
      "classStyle": "Poco",
      "generateDefaultValues": true,
      "generateDataAnnotations": true,
      "excludedTypeNames": [],
      "excludedParameterNames": [
        "Authorization",
        "Accept-Language"
      ],
      "handleReferences": false,
      "generateImmutableArrayProperties": false,
      "generateImmutableDictionaryProperties": false,
      "jsonSerializerSettingsTransformationMethod": null,
      "inlineNamedArrays": false,
      "inlineNamedDictionaries": false,
      "inlineNamedTuples": true,
      "inlineNamedAny": false,
      "generateDtoTypes": true,
      "generateOptionalPropertiesAsNullable": false,
      "templateDirectory": null,
      "typeNameGeneratorType": null,
      "propertyNameGeneratorType": null,
      "enumNameGeneratorType": null,
      "serviceHost": null,
      "serviceSchemes": null,
      "output": "../NSwagTestHarness.Client/gen/Client.g.cs"
    }
  }
}

The generated contracts for ProblemDetails and ValidationProblemDetails both generate AdditionalProperties which could be a problem with the properties conflicting:

    [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.11.0 (Newtonsoft.Json v12.0.0.0)")]
    public partial class ProblemDetails 
    {
        [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public System.Uri Type { get; set; }
    
        [Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string Title { get; set; }
    
        [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public int? Status { get; set; }
    
        [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string Detail { get; set; }
    
        [Newtonsoft.Json.JsonProperty("instance", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public System.Uri Instance { get; set; }
    
        private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
    
        [Newtonsoft.Json.JsonExtensionData]
        public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
        {
            get { return _additionalProperties; }
            set { _additionalProperties = value; }
        }
    
    
    }
    
    [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.11.0 (Newtonsoft.Json v12.0.0.0)")]
    public partial class ValidationProblemDetails : ProblemDetails
    {
        [Newtonsoft.Json.JsonProperty("errors", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public System.Collections.Generic.IDictionary<string, System.Collections.Generic.ICollection<string>> Errors { get; set; }
    
        private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
    
        [Newtonsoft.Json.JsonExtensionData]
        public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
        {
            get { return _additionalProperties; }
            set { _additionalProperties = value; }
        }
    
    
    }

My guess is that the disabling of CS0108 is hiding the warning.

#pragma warning disable 108 

Wouldn’t it make sense that NJsonSchema or NSwag see the inherited property/configuration for JsonExtensionData and not generate it?

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
RicoSutercommented, Apr 23, 2020

This is a serious bug i’d say.

2reactions
sdecoodtcommented, Apr 8, 2022

I ran into this issue with problem details as wel. It seems to have been partially fixed in #https://github.com/RicoSuter/NJsonSchema/issues/1447 but that does not cover deeper inheritance layers

@RicoSuter I’m thinking of having a crack at fixing this, is there any specific branch i should start from?

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found