为什么 Swagger 显示导入项目的端点,而不是主/启动项目

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

我有一个主要的 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)。

c# api swagger swagger-ui asp.net-core-6.0
2个回答
1
投票

经过几个小时的调查,我想出了一个解决方案(在 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] 的控制器/端点


1
投票

我想建议一个稍微简洁的解决方案。 为什么不根据组件来过滤控制器,而不是根据附加属性来过滤控制器呢?

在此示例中,位于名称不以“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>();
    });
    ...
© www.soinside.com 2019 - 2024. All rights reserved.