Swagger/Swashbuckle 无法识别请求模型中的 JObject
Swagger/Swashbuckle do not recognize JObject in request model
我的环境:Asp.NETWebAPI、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";
}
}
直接运行,swaggerui页面正确显示
sample picture, pls right click
但是如果我添加一个带有参数的 Post 动作,swagger ui 不会识别请求模型
UserModel 和 UserModelSex
/// <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 操作,并传递新的请求模型 UserModelSex,我得到报错,因为Override Method必须和parent Method有相同的param List,所以我改成这样
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");
}
}
招摇ui 不认识 JObject
sample picture, pls right click
如何在请求模型中显示UserModel和UserModeSex,如图2
最后还是自己解决了
- 添加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
我的环境:Asp.NETWebAPI、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";
}
}
直接运行,swaggerui页面正确显示
sample picture, pls right click
但是如果我添加一个带有参数的 Post 动作,swagger ui 不会识别请求模型
UserModel 和 UserModelSex
/// <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 操作,并传递新的请求模型 UserModelSex,我得到报错,因为Override Method必须和parent Method有相同的param List,所以我改成这样
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");
}
}
招摇ui 不认识 JObject
sample picture, pls right click
如何在请求模型中显示UserModel和UserModeSex,如图2
最后还是自己解决了
- 添加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