微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Swagger UI 不会在控制器的 GET 操作中为我的复杂类型参数呈现主体参数字段

如何解决Swagger UI 不会在控制器的 GET 操作中为我的复杂类型参数呈现主体参数字段

我有一个 ASP.NET Web API 2 项目,我在其中添加了 Swagger - Swashbuckle v5.6.0。一切正常。 Swagger UI 按预期呈现我的 API 的测试端点。

我在我的 API 中添加一个新的控制器。有一个带有复杂类型参数的 GET 操作。对于复杂类型,Web API 尝试从消息正文中读取值。这是认行为。

这是我的 GET 操作:

    [HttpGet]
    [Route("search")]
    [ResponseType(typeof(List<SearchModel>))]
    public IHttpActionResult Search(SearchModel searchOptions)
    {
        //....
        
        return Ok();
    }

而她是我的复杂类型:

public class SearchModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    [DataType(DataType.EmailAddress)]
    [EmailAddress]
    public string Email { get; set; }

    public string AddressLine1 { get; set; }

    public string City { get; set; }

    public string Telephone { get; set; }

    public string MobilePhone { get; set; }
}

问题:

但是 Swagger UI 不会在 GET 操作中为我的复杂类型呈现正文参数字段。对于 POSTPUT 操作,Swagger UI 按预期呈现正文参数字段,但不是我的 GET 操作中的复杂类型。

Screenshot of my GET action from Swagger UI

从截图中可以看出,Swagger UI 为我的复杂类型中的属性呈现查询参数字段,而不是像在 POSTPUT 的情况下为我的类型呈现正文参数字段.

从 Postman 进行测试并在请求正文中填充 json 时,我的 GET 操作运行良好。通过在 Visual Studio 中的 action 中设置断点,我可以看到值绑定到我的 action 参数中的对象。

Postman screenshot

我尝试使用 [FromBody](复杂类型的认值)装饰我的操作中的参数,但结果相同。

这是 Swagger 中的错误吗?还是我遗漏了什么?

解决方法

遗憾的是,您无法使用 Swagger 做您想做的事。您不能在 HTTP GET 方法中发送请求模型。但是,您可以将 swagger UI 更改为如下所示:

swagger GET with body

但是您将无法在控制器中接收模型。

这是 Swagger 开发人员中的一个已知问题,并在 2016 年进行了讨论,最终决定是 swagger 不支持 HTTP GET 方法中的请求正文。 Here is the link to the already closed issue.

这里有三个选项:

  • 保持方法不变,并在 Postman 中测试它,而不是在 Swagger 中。
  • 按照以下步骤实现上图,但请注意,它只会修复 UI 部分,并且当您按下 {{ 1}} 大摇大摆。
  • 使其成为 null 方法而不是 SearchModel

如何使 swagger UI 显示带有请求正文的 GET 方法:

首先,创建一个 Try it out! 类:

[HttpPost

然后你可以在控制器中装饰你的方法:

[HttpGet]

之后创建Attribute类(public class ModelInBodyAttribute : Attribute { public ModelInBodyAttribute(string modelName,string description,bool isRequired) { this.ModelName = modelName; this.Description = description; this.IsRequired = IsRequired; } public string ModelName { get; set; } public bool IsRequired { get; set; } public string Description { get; set; } } ):

[ModelInBody(modelName: nameof(SearchModel),description: "My model description",isRequired: true)]
[HttpGet]
[Route("search")]
[ResponseType(typeof(List<SearchModel>))]
public IHttpActionResult Search(SearchModel searchOptions)
{
    //....

    return Ok(new List<SearchModel>());
}

最后,不要忘记在IOperationFilter中注册ModelInBodyOperationFilter

public class ModelInBodyOperationFilter : IOperationFilter
{
    public void Apply(Operation operation,SchemaRegistry schemaRegistry,ApiDescription apiDescription)
    {
        var attribute = apiDescription.GetControllerAndActionAttributes<ModelInBodyAttribute>().FirstOrDefault();
        if (attribute == null)
        {
            return;
        }

        operation.parameters.Clear();
        operation.parameters.Add(new Parameter
        {
            name = attribute.ModelName,description = attribute.Description,@in = "body",required = attribute.IsRequired,schema = new Schema { @ref = $"#/definitions/{attribute.ModelName}" }
        });
    }
}

当您通过 swagger 发送请求时,您会注意到 IOperationFilter 部分是绝对正确的,但在您的控制器中仍然没有任何内容。
curle example

example of GET method with a body in controller

,

关于是否应该在 GET 请求中包含 PAYLOAD“正文内容”的讨论无休止。正如您提到的它由 HTTP 支持,但您会在互联网上发现很多人建议不要这样做。我猜那个 swagger 团队也希望你不要使用它。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。