我有一个主要的 API 项目(称为 CustomerLayer),其中仅包含一个控制器和一个端点(UserController/GetAll)。控制器继承自 ControllerBase 并拥有所有 DataAnnotations(Route、HttpGet 等)。 该项目已将另一个 API 项目(称为 ImporterLayer)导入到解决方案中。
当我运行该解决方案时,Swagger 成功显示“CustomerLayer”标题,但它显示导入项目 (ImporterLayer) 上控制器的所有端点,而不是显示主项目上唯一的现有端点。
解决方案启动属性设置为:选择“CustomerLayer”的单个启动项目。同时选择 CustomerLayer 项目作为启动项目。
这里是主项目(CustomerLayer)的Program.cs相关代码
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", typeof(Program).Assembly.GetName().Name);
options.RoutePrefix = "swagger";
options.DisplayRequestDuration();
});
app.Run();
我期望只看到主项目 CustomerLayer 的端点 (UserController/GetAll)。
经过几个小时的调查,我想出了一个解决方案(在 ChatGPT 的帮助下:)
我改变了:
builder.Services.AddSwaggerGen();
致:
builder.Services.AddSwaggerGen(c =>
{
c.DocumentFilter<SwaggerIgnoreFilter>();
});
创建了类“SwaggerIgnoreFilter”:
public class SwaggerIgnoreFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var contextApiDescription in context.ApiDescriptions)
{
var actionDescriptor = (ControllerActionDescriptor)contextApiDescription.ActionDescriptor;
if (!actionDescriptor.ControllerTypeInfo.GetCustomAttributes<LayerTwo>().Any() &&
!actionDescriptor.MethodInfo.GetCustomAttributes<LayerTwo>().Any())
{
var key = "/" + contextApiDescription.RelativePath.TrimEnd('/');
swaggerDoc.Paths.Remove(key);
}
}
}
}
并创建了属性:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class LayerTwo : Attribute
{
}
最后将属性 [LayerTwo] 添加到我需要的每个控制器或端点。
通过此解决方法,您将能够仅显示标有 [LayerTwo] 的控制器/端点
我想建议一个稍微简洁的解决方案。 为什么不根据组件来过滤控制器,而不是根据附加属性来过滤控制器呢?
在此示例中,位于名称不以“MyAssembly”开头的程序集中的所有控制器都将被隐藏:
internal class SwaggerDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var apiDescription in context.ApiDescriptions)
{
var controllerActionDescriptor = (ControllerActionDescriptor)apiDescription.ActionDescriptor;
// If the Assembly name of the controller DOES NOT starts with..
if (!controllerActionDescriptor.ControllerTypeInfo.Assembly.FullName.StartsWith("MyAssembly"))
{
var key = "/" + apiDescription.RelativePath.TrimEnd('/');
swaggerDoc.Paths.Remove(key); // Hides the Api
}
}
}
}
您也可以在运行时读取它,而不是硬编码“MyAssembly”字符串:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
在这里,为了完整起见,注册:
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Swagger API", Version = "v1" });
c.DocumentFilter<SwaggerDocumentFilter>();
});
...