Search code examples
c#asp.net-coreswaggerswashbuckle.aspnetcore

Using Swashbuckle for Asp.net core how can I add a response with generic type to the generated model list?


I have the following Response object:

    public class Response<T> where T : ResponseData
    {

        public bool Success { get; set; }
        public HttpStatusCode StatusCode { get; set; }
        public string ErrorCode { get; set; }
        public string ErrorDescription { get; set; }
        public T Data { get; set; }

        public Response(bool success, HttpStatusCode statusCode, string errorCode, string msg, T data = null)
        {
            Success = success;
            StatusCode = statusCode;
            ErrorCode = errorCode;
            ErrorDescription = msg;
            Data = data;
        }

The ResponseData class is just a base class:

    public class ResponseData
    {
    }

Then I have for example the following class:

    public class ResponseProduct: ResponseData
    {
        public int Id{ get; set; }

        public string Description { get; set; }
    }

On my controller I have the following:

        [HttpGet]
        [Route(ApiBaseConstants.MethodProduct)]
        [Consumes(MediaTypeNames.Application.Json)]
        [ProducesResponseType(typeof(Response<ResponseProduct>), StatusCodes.Status200OK)]
        public async Task<IActionResult> GetProduct()
        {
            return ParseResponse(await CurrentApi.GetProduct());
        }

The problem I have is that it doesn't generate on the schema the Response object instead it generates a ResponseProductResponse which is the Response< ResponseProduct > so I have the following schemas:

  • ResponseData
  • ResponseProduct
  • ResponseProductResponse

How can I have a Response instead of a ResponseProductResponse?


Solution

  • well , adding an SchemaFilter would work

    public class ResponseTypeSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (context.Type.IsGenericType && context.Type.GetGenericTypeDefinition() == typeof(Response<>))
            {
                var responseType = context.Type.GetGenericArguments()[0];
    
                if (responseType.IsGenericType && responseType.GetGenericTypeDefinition() == typeof(List<>))
                {
                    var itemType = responseType.GetGenericArguments()[0];
                    var itemSchema = context.SchemaGenerator.GenerateSchema(itemType, context.SchemaRepository);
                    schema.Type = "array";
                    schema.Items = itemSchema;
                }
                else
                {
                    schema.Reference = null;
                    schema.Properties.Clear();
                    schema.Type = "object";
                    var props = responseType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                    foreach (var prop in props)
                    {
                        schema.Properties[prop.Name] = context.SchemaGenerator.GenerateSchema(prop.PropertyType, context.SchemaRepository);
                    }
                }
            }
        }
    }
    

    and configure your swagger like

    services.AddSwaggerGen(swaggerOptions =>
            {
                swaggerOptions.SchemaFilter<ResponseTypeSchemaFilter>();
    
            });