Swagger UI在我的Controller的GET操作中不呈现我的复杂类型参数的主体参数字段

jv4diomz  于 2023-10-18  发布在  其他
关注(0)|答案(4)|浏览(163)

我有一个ASP.NET Web API 2项目,我已经向其中添加了Swagger - Swashbuckle v5. 6. 0。一切正常。Swagger UI按照预期为我的API呈现测试端点。
我在我的API中添加了一个新的Controller。有一个带有复杂类型参数的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操作中没有呈现我的复杂类型的body参数字段。对于POSTPUT操作,Swagger UI按预期呈现主体参数字段,但对于我的GET操作中的复杂类型则不然。

从屏幕截图中可以看出,Swagger UI呈现了我的复杂类型中属性的查询参数字段,而不是像POSTPUT那样呈现我的类型的主体参数字段。
我的GET操作在Postman测试并在请求体中填充JSON时工作正常。通过在Visual Studio中的action中设置断点,我可以看到值被绑定到action参数中的对象。

我尝试用[FromBody](这是复杂类型的默认值)装饰我的操作中的参数,但结果相同。
这是斯威格的一个bug吗还是我错过了什么?

krugob8w

krugob8w1#

可惜你不能对斯威格为所欲为不能在HTTP GET方法中发送请求模型。但是,您可以将swagger UI更改为如下所示:

但是你将无法在控制器中接收模型。
这是Swagger开发人员中的一个已知问题,并在2016年进行了讨论,最终决定是Swagger将不支持HTTP GET方法中的请求体。Here is the link to the already closed issue.
你有三个选择:

  • 保持方法不变,在Postman中测试它,但不在Swagger中测试。
  • 按照下面的步骤来实现上面的图片,但请注意,它只会修复UI部分,当你按下swagger中的Try it out!时,你总是会在控制器中得到nullSearchModel
  • 将其设置为[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; }
}

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

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

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

c.OperationFilter<ModelInBodyOperationFilter>();

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

1mrurvl1

1mrurvl12#

关于是否应该在GET请求中包含PAYLOAD“Body content”,有无数的讨论。正如你提到的它是由HTTP支持,但你会发现在互联网上,许多人建议不要这样做。我猜那支神气活现的队伍也希望你不要用它。

lx0bsm1f

lx0bsm1f3#

这是一个有点晚的答复,但如果你能够装饰控制器与[APIController], Swagger 将显示一个不同的ui为复杂的类型。
APIController

k5ifujac

k5ifujac4#

GET、HEAD和REQ上的请求体不能互操作的事实已经得到澄清。(第9.3.1、9.3.2和9.3.5节)
https://www.rfc-editor.org/rfc/rfc9110#appendix-B.3-8
不建议在GETHEADDELETE上包含任何类型的请求正文或内容。

相关问题