【问题标题】:Swagger/Swashbuckle do not recognize JObject in request modelSwagger/Swashbuckle 无法识别请求模型中的 JObject
【发布时间】:2021-02-22 16:29:00
【问题描述】:

我的环境:Asp.NET WebAPI、NET Framework 4.5.2、Swashbuckle.Core 5.6.0

由于某种原因,我的控制器必须继承之前的同一个控制器,像这样

public class User100Controller : ApiController
{
    [HttpGet]
    [AllowAnonymous]
    public virtual string Get()
    {
        return "1.0.0";
    }
}

public class User101Controller : User100Controller
{
    [HttpGet]
    [AllowAnonymous]
    public override string Get()
    {
        return "1.0.1";
    }
}

直接运行,swagger ui页面正确显示

sample picture, pls right click

但是如果我添加一个带有参数的 Post Action,swagger ui 不会重新识别请求模型

UserModelUserModelSex

/// <summary>
/// UserModel
/// </summary>
public class UserModel
{
    /// <summary>
    /// Name
    /// </summary>
    public string name { get; set; } = string.Empty;

    /// <summary>
    /// Age
    /// </summary>
    public int age { get; set; } = 0;
}

/// <summary>
/// UserModelSex
/// </summary>
public class UserModelSex : UserModel
{
    /// <summary>
    /// Sex
    /// </summary>
    public int sex { get; set; } = -1;
}

User100Controller

[HttpPost]
[SwaggerResponse(200, "success", typeof(UserModel))]
public virtual IHttpActionResult SaveUser([FromBody] UserModel model)
{
    if (string.IsNullOrEmpty(model.name) || model.age == 0)
    {
        return Ok("error");
    }

    //...
    return Ok("success");
}

sample picture, pls right click

这是正确的效果,现在如果我在User101ontroller中覆盖这个SaveUser Action,并传递新的请求模型UserModelSex,我得到一个错误,因为Override Method必须与父方法具有相同的参数列表,所以我像这样更改它

public class User100Controller : ApiController
{
    [HttpPost]
    [SwaggerResponse(200, "success", typeof(UserModel))]
    public virtual IHttpActionResult SaveUser([FromBody] JObject json)
    {
        var model = json.ToObject<UserModel>();
        if (string.IsNullOrEmpty(model.name) || model.age == 0)
        {
            return Ok("error");
        }

        //...
        return Ok("success");
    }
}

public class User101Controller : User100Controller
{
    [HttpPost]
    [SwaggerResponse(200, "success", typeof(UserModelSex))]
    public override IHttpActionResult SaveUser([FromBody] JObject json)
    {
        var model = json.ToObject<UserModelSex>();
        if (string.IsNullOrEmpty(model.name) || model.age == 0 || model.sex == -1)
        {
            return Ok("error");
        }

        //...
        return Ok("success");
    }
}

swagger ui 无法识别 JObject

sample picture, pls right click

如何在请求模型中显示UserModelUserModeSex,如图2

【问题讨论】:

    标签: swagger swagger-ui swashbuckle webapi


    【解决方案1】:

    最后我自己解决了

    • 添加 SwaggerRequestModelAttribute.cs
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class SwaggerRequestModelAttribute : Attribute
    {
        public Type RequestModel { get; private set; }
    
        public string ModelName { get; private set; }
    
        public SwaggerRequestModelAttribute(Type requestModel)
        {
            RequestModel = requestModel;
            ModelName = requestModel.Name;
        }
    }
    
    • 然后,将 [SwaggerRequestModel] 标记到控制器
    [HttpPost]
    [SwaggerRequestModel(typeof(UserModel))]
    public virtual IHttpActionResult SaveUser([FromBody] JObject json)
    {
        var model = json.ToObject<UserModel>();
        if (string.IsNullOrEmpty(model.name) || model.age == 0)
        {
            return Ok("error");
        }
    
        //...
        return Ok("success");
    }
    
    • 添加 ModelInBodyOperationFilter.cs
    public class ModelInBodyOperationFilter : IOperationFilter
    {
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            if (operation.parameters == null) operation.parameters = new List<Parameter>();
    
            var attribute = apiDescription.GetControllerAndActionAttributes<SwaggerRequestModelAttribute>();
            if (attribute.Any())
            {
                if (operation.parameters.Count > 0 && operation.parameters[0].schema.type == "object")
                {
                    if (!schemaRegistry.Definitions.ContainsKey(attribute.First().ModelName))
                        schemaRegistry.GetOrRegister(attribute.First().RequestModel);
    
                    operation.parameters.RemoveAt(0);
                    operation.parameters.Add(new Parameter
                    {
                        name = "-",
                        @in = "body",
                        required = true,
                        schema = new Schema { @ref = $"#/definitions/{attribute.First().RequestModel.Namespace}.{attribute.First().ModelName}" }
                    });
                }
            }
        }
    }
    
    • 另外,在 SwaggerConfig.Register() 中
    c.UseFullTypeNameInSchemaIds();
    c.OperationFilter<ModelInBodyOperationFilter>();
    
    • 最后,运行应用并预览

    sample picture, pls right click

    【讨论】:

      猜你喜欢
      • 2019-10-23
      • 1970-01-01
      • 2015-05-08
      • 2013-02-19
      • 2021-11-16
      • 1970-01-01
      • 2016-08-10
      • 2018-12-10
      • 1970-01-01
      相关资源
      最近更新 更多