【问题标题】:ASP.NET Core 3.0 / Swashbuckle : restrict responses content types globallyASP.NET Core 3.0 / Swashbuckle:全局限制响应内容类型
【发布时间】:2019-11-21 10:59:09
【问题描述】:

这与How do I set or remove the Default Response Content Type Using SwashBuckle 基本相同的问题,但针对.NET Core 3.0

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

这很好,但是 swagger.json 包含每个操作的多种响应内容类型(text/plain + application/json + text/json)

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

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

【问题讨论】:

    标签: c# asp.net-core swashbuckle asp.net-core-3.0


    【解决方案1】:

    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>();  
            });
    

    【讨论】:

    • 抱歉投反对票,但这个答案没有回答我的问题(与接受的答案相反),只是解释过滤器(我已经在问题中提到)
    【解决方案2】:

    您可以创建自定义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>());
    

    【讨论】:

    • 这个想法可行,但对于新的 5.0.0-rc4,您需要使用 operation.RequestBody.Content 和 operation.Responses[].Content
    • 太好了,您可以将此注释添加到答案中
    • @ChristopheBlin 我需要在哪里使用它们?
    • @FrancoScarpa 您向 services.AddSwagerGen 注册过滤器,如答案中所述
    【解决方案3】:

    这在 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>();  
            });
    

    【讨论】:

      【解决方案4】:

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

      This MSDN 详细介绍,但关键在于这样做:

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

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

      注意:记得安装/导入Microsoft.AspNetCore.Mvc.Formatters

      【讨论】:

        【解决方案5】:

        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");
                }
            }
        }
        

        为字符串操作生成的招摇:

        "/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"
                        }
                      }
                    }
                  }
                }
              }
            },
        

        【讨论】:

        • 我认为 response.Content 是一个字典,即 Key 是唯一的。直接删除将需要/不需要 linq Where/foreach/remove,因为只有 0 或 1 并且如果没有键,remove 不会抛出..
        • @CaiusJard 这是一个原型 :) 最终版本可能更简单:if (response.Content.ContainsKey("text/plain")) response.Content.Remove("text/plain");
        猜你喜欢
        • 2016-09-12
        • 1970-01-01
        • 2020-05-10
        • 2018-06-27
        • 2019-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-01
        相关资源
        最近更新 更多