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

bah*_*mzy 3 asp.net swagger swagger-ui asp.net-web-api2 swashbuckle

我有一个 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();
    }
Run Code Online (Sandbox Code Playgroud)

她是我的复杂类型:

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; }
}
Run Code Online (Sandbox Code Playgroud)

问题:

但 Swagger UI 不会在操作中呈现我的复杂类型的主体参数字段GET。ForPOSTPUTactions Swagger UI 按预期呈现主体参数字段,但不适用于我的GET操作中的复杂类型。

Swagger UI 中的 GET 操作的屏幕截图

从屏幕截图中可以看出,Swagger UI 为我的复杂类型中的属性呈现查询参数字段,而不是像在POST和的情况下为我的类型呈现主体参数字段PUT

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

邮递员截图

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

这是 Swagger 中的错误吗?或者我错过了什么?

G.D*_*mov 5

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

用身体大摇大摆地GET

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

这是 Swagger 开发人员中的一个已知问题,并于 2016 年进行了讨论,最终决定是 swagger 不支持 HTTP GET 方法中的请求正文。这是已关闭问题的链接。

您在这里有三个选择:

  • 保持该方法不变,并在 Postman 中测试它,但不在 Swagger 中测试。
  • 按照以下步骤实现上图,但请注意,它只会修复 UI 部分,当您按下swagger时,您将始终处于null SearchModel控制器中。Try it out!
  • 使其成为一种[HttpPost方法而不是[HttpGet].

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

首先,创建一个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; }
}
Run Code Online (Sandbox Code Playgroud)

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

[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>());
}
Run Code Online (Sandbox Code Playgroud)

之后创建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}" }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,不要忘记IOperationFilter注册SwaggerConfig

c.OperationFilter<ModelInBodyOperationFilter>();
Run Code Online (Sandbox Code Playgroud)

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

控制器中带有主体的 GET 方法示例