Swashbuckle.AspNetCore.SwaggerGen ISchemaGenerator.GenerateSchema 生成一个空架构

问题描述 投票:0回答:1

我在 .NET 8 服务中使用

Swashbuckle.AspNetCore.Swagger 6.6.2
和自定义
IOperationFilter
来为我的 API 生成请求示例。在我的过滤器中,我尝试使用
SchemaRepository
方法为不在我的
ISchemaGenerator.GenerateSchema(Type modelType, SchemaRepository schemaRepository)
中的类型手动生成架构,但手动生成的类型架构始终为空,没有填充任何属性。

这就是我生成架构的方式:

private OpenApiSchema GenerateSpecializedSchema(Type modelType, SchemaRepository schemaRepository, ISchemaGenerator schemaGenerator)
{
    OpenApiSchema schema = schemaGenerator.GenerateSchema(modelType, schemaRepository);
    // Schema is empty at this point
    return schema;
}

在我的自定义中使用它

IOperationFilter

public class MyCustomOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        // Retrieve the exact type I want from a custom attribute (details omitted for simplicity)
        var modelType = ...;

        // Generate the schema for the specified type
        var schema = GenerateSpecializedSchema(modelType, context.SchemaRepository, context.SchemaGenerator);
    }
}

我尝试生成如下所示的模式的类类型示例:

public class MyClassExample
{
    public string PropertyA { get; set; }
    public string PropertyB { get; set; }
}

当我检查生成的模式时,它是空的——这意味着里面没有属性。然而,

MyClassExample
是一个简单的 POCO,具有一些公共属性,我希望这些属性出现在生成的架构中。

对于 MyClassExample,生成的 OAS JSON 文件如下所示:

 ...
 "components": {
    "schemas": {
      "MyClassExample": {}
       ...
    }
 ...

我尝试过的:

  • 我已经调试了代码,看起来 ISchemaGenerator.GenerateSchema 返回了一个没有任何属性的空 OpenApiSchema。
  • 我已验证 modelType 正确并指向 MyClassExample。
  • 我已检查该类型是否是公共且可访问的。

我期望收到具有模型类型属性的模式。

c# swagger swashbuckle.aspnetcore
1个回答
0
投票

我在本地进行测试,这是我的测试项目的结构和测试结果。

enter image description here

测试结果

enter image description here

这是详细代码

1.MyCustomOperationFilter.cs

using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace MyTest
{
    public class MyCustomOperationFilter : IOperationFilter
    {
        private readonly SchemaGeneratorOptions _schemaGeneratorOptions;

        public MyCustomOperationFilter(IOptions<SchemaGeneratorOptions> schemaGeneratorOptions)
        {
            _schemaGeneratorOptions = schemaGeneratorOptions.Value;
        }
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            foreach (var parameterDescription in context.ApiDescription.ParameterDescriptions)
            {
                var parameterType = parameterDescription.Type;
                var schema = GenerateSpecializedSchema(parameterType, context.SchemaRepository, context.SchemaGenerator);

                var openApiParameter = operation.Parameters.FirstOrDefault(p => p.Name == parameterDescription.Name);
                if (openApiParameter != null)
                {
                    openApiParameter.Schema = schema;
                }
            }

            foreach (var responseType in context.ApiDescription.SupportedResponseTypes)
            {
                var returnType = responseType.Type;
                var schema = GenerateSpecializedSchema(returnType, context.SchemaRepository, context.SchemaGenerator);

                var statusCode = responseType.StatusCode.ToString();

                if (operation.Responses.ContainsKey(statusCode))
                {
                    var response = operation.Responses[statusCode];
                    response.Content["application/json"] = new OpenApiMediaType
                    {
                        Schema = schema
                    };
                }
                else
                {
                    operation.Responses[statusCode] = new OpenApiResponse
                    {
                        Description = "Success",
                        Content = new Dictionary<string, OpenApiMediaType>
                        {
                            ["application/json"] = new OpenApiMediaType
                            {
                                Schema = schema
                            }
                        }
                    };
                }
            }
        }

        private OpenApiSchema GenerateSpecializedSchema(Type modelType, SchemaRepository schemaRepository, ISchemaGenerator schemaGenerator)
        {
            var schemaId = _schemaGeneratorOptions.SchemaIdSelector(modelType);

            if (schemaRepository.Schemas.ContainsKey(schemaId))
            {
                schemaRepository.Schemas.Remove(schemaId);
            }

            OpenApiSchema schema = schemaGenerator.GenerateSchema(modelType, schemaRepository);
            return schema;
        }
    }
}

2.Program.cs

using MyTest;
using Swashbuckle.AspNetCore.SwaggerGen;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

builder.Services.Configure<SchemaGeneratorOptions>(options =>
{
    options.SchemaIdSelector = type => type.FullName;
});

builder.Services.AddSwaggerGen(c =>
{
    c.OperationFilter<MyCustomOperationFilter>();
    c.CustomSchemaIds(type => type.FullName); 
});



var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

3.MyClassExample.cs

namespace MyTest.Models
{
    public class MyClassExample
    {
        public string? PropertyA { get; set; }
        public string? PropertyB { get; set; }
    }
}

4.WeatherForecastController.cs

using Microsoft.AspNetCore.Mvc;
using MyTest.Models;

namespace MyTest.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }

        // Enable MyClassExample
        [HttpGet("GetMyClassExample")]
        public IEnumerable<MyClassExample> Get1()
        {
            return Enumerable.Range(1, 5).Select(index => new MyClassExample
            {
                PropertyA = DateOnly.FromDateTime(DateTime.Now.AddDays(index)).ToString(),
                PropertyB = Random.Shared.Next(-20, 55).ToString()
            })
            .ToArray();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.