I am facing an issue while trying to add a format attribute to each definition schema in my code using Swagger using Swashbuckle annotation [SwaggerSchema(Format = nameof(...))]
. The value of the format attribute should be the name of the schema itself. Here's what I have tried:
[SwaggerSchema(Format = nameof(User))]
public class User {
// implementation
}
This works fine and results in the following schema output:
"User": {
"format": "User",
"type": "object",
...
}
However, I encountered a problem when working with classes that have generic parameters, such as ResponseList<T>
which represents a list of response type. With the previous implementation, all schemas of ResponseList<...>
have the same format name, which is "ResponseList", as shown below:
"ResponseList<User>: {
"format": "ResponseList",
...
}
"ResponseList<Product>: {
"format": "ResponseList",
...
}
But my desired goal is to have schemas like this:
"ResponseList<User>: {
"format": "ResponseListUser",
...
}
"ResponseList<Product>: {
"format": "ResponseListProduct",
...
}
```
Is there any way to achieve this? Any help would be appreciated.
Instead of using the [SwaggerSchema]
attribute, define a custom ISchemaFilter
that modifies the Schema object generated by Swashbuckle for each type. This is the implementation which handles nested generic types like ResponseList<Class<User>>
:
public class GenericTypeSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsGenericType)
{
var typeName = context.Type.Name.Split('`')[0];
var typeArgs = context.Type.GetGenericArguments();
var formatValue = $"{typeName}";
foreach (var typeArg in typeArgs)
{
formatValue += $"{GetFormatValue(typeArg)}";
}
schema.Format = formatValue;
}
}
private static string GetFormatValue(Type type)
{
if (!type.IsGenericType)
{
return type.Name.Replace(".", "_");
}
var typeName = type.Name.Split('`')[0];
var typeArgs = type.GetGenericArguments();
var formatValue = $"{typeName}";
foreach (var typeArg in typeArgs)
{
formatValue += $"{GetFormatValue(typeArg)}";
}
return formatValue;
}
}
In this implementation, we've added a new method called GetFormatValue
that recursively processes each generic type parameter. If the type is not a generic type, we simply return its name. If it is a generic type, we extract its base name and process each type argument recursively.
To use this updated filter with Swashbuckle, you can register it in your Swagger configuration like this:
services.AddSwaggerGen(c =>
{
c.SchemaFilter<GenericTypeSchemaFilter>();
});