Reputation: 51
I have a controller like below having circular reference in class B.
This is happening because Swashbuckle's jsonserilalizer's setting is set to
ReferenceLoopHandling = ReferenceLoopHandling.Error
and I didn't find any way to override this setting.
I am using Swashbuckle 5.6.0 in an ASP.NET MVC application.
public class IssueController : ApiController
{
[HttpGet]
[Route("A")]
public A Get(A input)
{
return new A();
}
}
public class A
{
public virtual B prop1 { get; set; }
}
public class B
{
public virtual B Parent { get; set; }
}
Upvotes: 2
Views: 712
Reputation: 119
In my case it turned out, that the Stackoverflow exception wasn't caused by the jsonserializer, but by the previous step (when the Swashbuckle schema gets created before json gets serialized). Circle References doesn't seem to work yet with Swashbuckle (in Swashbuckle for it seems to be fixed btw). To fix this, you have to copy the HandleFromUriParamsRecurseSave
and add this (with the other filters) to the operations:
private static SwaggerDocument BuildSwaggerDocument()
{
...
var operationFilters = new List<IOperationFilter> {
new HandleFromUriParamsRecurseSave(20),
...
};
}
In the copied HandleFromUriParamsRecurseSave just add a maxrecurselength property, which fits your case and you shouldn't have the StackOverflow error any more:
private void ExtractAndAddQueryParams(
Schema sourceSchema,
string sourceQualifier,
bool? sourceRequired,
SchemaRegistry schemaRegistry,
ICollection<Parameter> operationParams)
{
foreach (var property in sourceSchema.properties)
{
...
var recurseCount = sourceQualifier.Count(t => t == '.');
if (schema.@ref != null && recurseCount < _maxRecurseLength)
{
ExtractAndAddQueryParams(schemaRegistry.Definitions[[email protected]("#/definitions/", "")], sourceQualifier + ToCamelCase(property.Key) + ".", flag, schemaRegistry, operationParams);
}
else
{
...
}
}
}
}
A further workaround I tried, but unfortunately didn't solve the issue, was to add a stack and everytime I detected a loop, added the right schema definition just one time (maybe someone sees the problem):
private void ExtractAndAddQueryParams(
Stack<string> sourceSchemaNames,
Schema sourceSchema,
string sourceQualifier,
bool? sourceRequired,
SchemaRegistry schemaRegistry,
ICollection<Parameter> operationParams)
{
if (sourceSchemaNames.Count > _maxRecurseLength) {
return;
}
foreach (var property in sourceSchema.properties)
{
var schema = property.Value;
var readOnly = schema.readOnly;
if (readOnly != true)
{
var flag = sourceRequired == true && sourceSchema.required != null && sourceSchema.required.Contains(property.Key);
var recursionDetected = _disableRecursion && sourceSchemaNames.Contains(schema.@ref);
if (schema.@ref != null && !recursionDetected)
{
sourceSchemaNames.Push(schema.@ref);
ExtractAndAddQueryParams(sourceSchemaNames, schemaRegistry.Definitions[[email protected]("#/definitions/", "")],
sourceQualifier + ToCamelCase(property.Key) + ".", flag, schemaRegistry,
operationParams);
sourceSchemaNames.Pop();
}
else
{
...
if (recursionDetected) {
partialSchema.type = "object";
partialSchema.@ref = schema.@ref;
}
operationParams.Add(partialSchema);
}
}
}
}
}
Upvotes: 2