我在 .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": {}
...
}
...
我尝试过的:
我期望收到具有模型类型属性的模式。
我在本地进行测试,这是我的测试项目的结构和测试结果。
测试结果
这是详细代码
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();
}
}
}