I have a custom generic type that looks roughly like this:
public struct Foo<T>
{
public int Value { get; }
public string Signature { get; }
public Type Type { get; }
}
This type is is used in request and response bodies and in controller action parameters. Everything is configured so that it's serialized as a string, and it works fine with model binding and JSON serialization. The type has a TypeConverter
associated with it, which takes care of converting it to and from a string.
However, the Swagger schema still represents it as an object with 3 properties. The Type
property is also expanded, which pulls all the System.Reflection
types exposed directly or indirectly by Type
.
How can I avoid this and expose my type as a string?
First solution attempted: using MapType
I tried to use MapType
; it works fine if I specify the generic type argument, but doesn't work with the open generic type:
c.MapType(typeof(Foo<Something>), () => new OpenApiSchema { Type = "string" }); // Works
c.MapType(typeof(Foo<>), () => new OpenApiSchema { Type = "string" }); // Doesn't work
How can I apply the mapping to Foo<T>
, for any T
?
Current workaround
So far the only workaround I have is pretty ugly :
class SchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type is Type type &&
type.IsGenericType &&
!type.IsGenericTypeDefinition &&
type.GetGenericTypeDefinition() == typeof(Foo<>))
{
schema.Type = "string";
schema.Properties.Clear();
}
else if (context.Type?.FullName.StartsWith("System.", StringComparison.Ordinal) is true
&& context.SchemaRepository.TryGetIdFor(context.Type, out var schemaId))
{
DocFilter.SchemaIdsToRemove.Add(schemaId);
}
}
}
class DocFilter : IDocumentFilter
{
public static readonly HashSet<string> SchemaIdsToRemove = new HashSet<string>();
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var schemaId in SchemaIdsToRemove)
{
swaggerDoc.Components.Schemas.Remove(schemaId);
}
}
}