I am using NSwag to generate and serve an OpenAPI document. for the most part it generates just fine. however, sometimes when my coworker tries to serve the page locally, the JSON created includes $type
properties (but only sometimes). Here is an partial sample JSON snippet showing what I mean:
"paths": {
"$type": "NSwag.Collections.ObservableDictionary`2[[System.String, System.Private.CoreLib],[NSwag.OpenApiPathItem, NSwag.Core]], NSwag.Core",
"/api/Export/delimited/fetch/{fileName}": {
"post": {
"$type": "NSwag.OpenApiOperation, NSwag.Core",
"tags": {
"$type": "System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib",
"$values": [
"Export"
]
},
"operationId": "Export_ExportClaimsToDelimitedTextFile",
"parameters": {
"$type": "System.Collections.Generic.List`1[[NSwag.OpenApiParameter, NSwag.Core]], System.Private.CoreLib",
"$values": [
{
"$type": "NSwag.OpenApiParameter, NSwag.Core",
"name": "fileName",
"in": "path",
"required": true,
"schema": {
"$type": "NJsonSchema.JsonSchema, NJsonSchema",
"type": "string"
},
"x-position": 1
}
]
},
"requestBody": {
"$type": "NSwag.OpenApiRequestBody, NSwag.Core",
"x-name": "requestWithFriends",
"content": {
"$type": "NSwag.Collections.ObservableDictionary`2[[System.String, System.Private.CoreLib],[NSwag.OpenApiMediaType, NSwag.Core]], NSwag.Core",
"application/json": {
"$type": "NSwag.OpenApiMediaType, NSwag.Core",
"schema": {
"$type": "NJsonSchema.JsonSchema, NJsonSchema",
"oneOf": {
"$type": "System.Collections.ObjectModel.ObservableCollection`1[[NJsonSchema.JsonSchema, NJsonSchema]], System.ObjectModel",
"$values": [
{
"$type": "NJsonSchema.JsonSchema, NJsonSchema",
"$ref": "#/components/schemas/ExportRequest"
}
]
}
}
}
},
"required": true,
"x-position": 2
},
"responses": {
"$type": "NSwag.Collections.ObservableDictionary`2[[System.String, System.Private.CoreLib],[NSwag.OpenApiResponse, NSwag.Core]], NSwag.Core",
"200": {
"$type": "NSwag.OpenApiResponse, NSwag.Core",
"description": "",
"content": {
"$type": "System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[NSwag.OpenApiMediaType, NSwag.Core]], System.Private.CoreLib",
"application/octet-stream": {
"$type": "NSwag.OpenApiMediaType, NSwag.Core",
"schema": {
"$type": "NJsonSchema.JsonSchema, NJsonSchema",
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
I expected Json more like this:
"paths": {
"/api/Export/delimited/fetch/{fileName}": {
"post": {
"tags": [
"Export"
],
"operationId": "Export_ExportClaimsToDelimitedTextFile",
"parameters": [
{
"name": "fileName",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"x-position": 1
}
],
"requestBody": {
"x-name": "requestWithFriends",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExportClaimsRequestWithDealers"
}
}
},
"required": true,
"x-position": 2
},
"responses": {
"200": {
"description": "",
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
My intention is to use the Swagger.json to generate typescript files using NSwag's tools. However these $type
properties break that process.
Ihis is a screen shot of the error it produced when I attempt to parse the first JSON:
My attempts to correct this issue have not been very fruitful. ChatGPT seems to indicate that it has something to do with Newtonsoft.Json to specify the type of the object and that I can disable it using this bit of code:
services.AddOpenApiDocument(config =>
{
// Disable the $type properties in the Swagger JSON
config.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
});
However when I try that I discover that SerializerSettings
is null
at runtime. Regardless, such a thing wouldn't explain why it only occurred sometimes. I thought it might have something to do with different package versions but that's hard to verify.
I am looking for any advice as to how to diagnose and correct this issue. Even a consistent way to temporarily reset the app to escape this state would be helpful.
The appearance of $type
properties in the JSON is indeed related to Newtonsoft.Json's settings for TypeNameHandling
. By default, these settings should not be generating the $type
properties, but sometimes the settings can be globally overridden, causing the unexpected behavior.
Here's a multi-step approach to diagnose and correct this issue:
Explicitly Set SerializerSettings:
If SerializerSettings
is null at runtime, then you need to initialize it before setting properties on it. You can do this as follows:
services.AddOpenApiDocument(config =>
{
if (config.SerializerSettings == null)
{
config.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings();
}
config.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
});
Ensure Consistency Across Environments: You mentioned that this issue is intermittent, particularly between your environment and your coworker's. Here are some steps to ensure consistency:
Startup.cs
or other configuration files.Global Configuration:
It's possible that there's some global configuration or another service in your application that modifies the default JsonSerializerSettings
. Look for any other code in your project that modifies JsonConvert.DefaultSettings
or sets TypeNameHandling
properties.
Refresh & Rebuild: Sometimes the issues can be related to build caches. You can:
bin
and obj
directories from your project and rebuild it.Logging & Diagnostics:
If you're still facing the issue, consider adding diagnostic logs. For instance, right before your OpenAPI document is generated, log the value of config.SerializerSettings.TypeNameHandling
. This will help you understand if the setting is being changed somewhere else.
Fallback: Manual Cleanup:
As a temporary measure (not a permanent solution), you can write a middleware or a post-processing step that intercepts the generated Swagger JSON and removes all $type
properties. But this should be your last resort.
Remember, the key is to ensure that the environment and settings are consistent across all development machines. By following these steps, you should be able to identify the root cause and rectify the issue.