ASP.NET Core 3.0 / Swashbuckle:全局限制响应内容类型

ASP.NET Core 3.0 / Swashbuckle : restrict responses content types globally

这基本上是与 相同的问题,但对于 .NET Core 3.0

默认情况下,在 .NET Core 3.0 中,您使用 services.AddControllers() 配置 Web api,然后使用 services.AddSwaggerGen() + app.UseSwagger()[=18 配置带有 swashbuckle 的 swagger =]

工作正常,但是 swagger.json 包含每个操作的多个响应内容类型 (text/plain + application/json + text/json)

I know 我可以通过在我的操作中添加 [Produces][Consumes] 来限制这些响应内容类型,但我想在每个操作中避免这种情况(即我想在全球范围内这样做)

请注意,我最好使用 System.Text.Json,但如果您有一个仅适用于 Newtonsoft.JSON 的解决方案,那总比没有好 ;)

您可以创建自定义 filter for swagger

internal class AssignContentTypeFilter : IOperationFilter
{

    public void Apply(Operation operation, OperationFilterContext context)
    {
        operation.Consumes.Clear();
        operation.Consumes.Add("application/json");

        operation.Produces.Clear();
        operation.Produces.Add("application/json");
    }
}

然后

services.AddSwaggerGen(cfg => cfg.OperationFilter<AssignContentTypeFilter>());

Swashbuckle.AspNetCore.SwaggerGen 5.0 使用 OpenApiOperation 来描述 API 操作。

using System.Collections.Generic;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

public class AssignContentTypeFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.Responses.ContainsKey("200"))
        {
            operation.Responses.Clear();
        }

        var data = new OpenApiResponse
        {
            Description = "Ok",
            Content = new Dictionary<string, OpenApiMediaType>
            {
                ["application/json"] = new OpenApiMediaType(),
                ["application/xml"] = new OpenApiMediaType(),
            }
        };

        operation.Responses.Add("200", data);
    }
}

在Startup.cs

        services.AddSwaggerGen(q =>
        {
            q.SwaggerDoc("v1", new OpenApiInfo
            {
                Title = "mytitle",
                Version = "v1",
            });
            q.OperationFilter<AssignContentTypeFilter>();  
        });

Swashbuckle.AspNetCore.SwaggerGen 6+ 的版本。仅删除 text/plain 内容类型。在我的案例中适用于字符串结果。

internal class RemoveTextContentOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        foreach (var (_, response) in operation.Responses)
        {
            if (response.Content.ContainsKey("text/plain"))
                response.Content.Remove("text/plain");
        }
    }
}

为字符串操作生成的 swagger:

"/api/news/{newsArticleId}/file-link": {
      "get": {
        "tags": [
          "NewsApi"
        ],
        "operationId": "NewsApi_GetUploadFileLink",
        "parameters": [
          {
            "name": "newsArticleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "500": {
            "description": "Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              },
              "text/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },

这就是我在 Swashbuckle.AspNetCore.SwaggerGen 5.0 中工作的方式:

    using System.Collections.Generic;
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;

    internal class ContentTypeOperationFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            if (operation.RequestBody == null)
            {
                return;
            }

            operation.RequestBody.Content = new Dictionary<string, OpenApiMediaType>
            {
                { "application/json",  new OpenApiMediaType() }
            };

            foreach (var response in operation.Responses)
            {
                response.Value.Content = new Dictionary<string, OpenApiMediaType>
                {
                    { "application/json",  new OpenApiMediaType() }
                };
            }
        }
    }

Startup.cs(根据 sjokkogutten 的回答修改):

        services.AddSwaggerGen(q =>
        {
            q.SwaggerDoc("v1", new OpenApiInfo
            {
                Title = "mytitle",
                Version = "v1",
            });
            q.OperationFilter<ContentTypeOperationFilter>();  
        });

text/plain 最终出现在生成的 swagger/openapi 规范中,因为默认情况下 API 控制器有一个 StringOutputFormatter(来自 Microsoft.AspNetCore.Mvc.Formatters 命名空间)可用。

This MSDN 进行了详细介绍,但关键在于通过执行以下操作:

services.AddControllers(options =>
{
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
});

..(可能在你的 Startup/ConfigureServices 中)你删除了相关的格式化程序并且 text/plain 不再出现在生成的 swagger 文档中

注意:记得要install/importMicrosoft.AspNetCore.Mvc.Formatters