测试我的Web API(nuget包Microsoft.AspNetCoreAll 2.0.5)我在使用注释进行模型验证时遇到了一些奇怪的问题。
我有(例如)这个控制器:
[HttpPost]
public IActionResult Create([FromBody] RequestModel request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// create
request.Name.DoSomething();
return Created(...);
}
我按如下方式定义了我的RequestModel:
public class RequestModel
{
[Required]
public string Name {get; set};
}
我的问题虽然我将RequestModel.Name定义为[Required]但它是null(如果身体的json中不存在Name。我认为不应该发生,因为它被标记为[Required]并自动显示为ModelState错误。
鉴于this link to the specs他们使用Bind(....)。
所以我的问题? 我是否必须每次都启用它,或者它应该是开箱即用还是打算如何使用它?
如果我用[Required]注释它,我会假设至少ModelState.IsValid如果不存在则返回false。
在我有多个对象互相嵌套的情况下,在链接中使用Bind似乎有点复杂。
编辑1:创建了MVC数据验证测试床 为了更好地可视化我的意思,让每个人都可以轻松地自己进行实验,我在GitHub上创建了小型演示.NET Core MVC data validation test bed。
您可以下载代码,使用VS 2017启动它,然后使用swagger ui自行尝试。
拥有这个模型:
public class StringTestModel2
{
[Required]
public string RequiredStringValue { get; set; }
}
使用该控制器进行测试:
[HttpPost("stringValidationTest2")]
[SwaggerOperation("StringValidationTest2")]
public IActionResult StringValidationTest2([FromBody] StringTestModel2 request)
{
LogRequestModel("StringValidationTest2", request);
if (!ModelState.IsValid)
{
LogBadRequest(ModelState);
return BadRequest(ModelState);
}
LogPassedModelValidation("StringValidationTest2");
return Ok(request);
}
结果远远超出预期:
离开我(现在),得出以下结论之一:
答案 0 :(得分:2)
你自动获得ModelValidation作为使用/派生控制器的一部分(我相信它是在MVC中间件中)但不幸的是,这不包括空检查。因此,您需要显式检查参数是否为NULL以及ModelState检查。
[HttpPost]
public IActionResult Create([FromBody] RequestModel request)
{
if (request == null || !ModelState.IsValid)
{
return BadRequest(ModelState);
}
...
答案 1 :(得分:1)
我假设您使用
services.AddMvc();
所以它应该默认工作。
但它并不像你期望的那样工作:它不是返回400状态代码,而是使模型状态无效并让你管理动作结果。 您可以创建一个属性类来自动返回"错误请求"
internal class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(
new ApiError(
string.Join(" ",
context.ModelState.Values
.SelectMany(e => e.Errors)
.Select(e => e.ErrorMessage))));
}
}
}
其中ApiError
是用于错误结果的自定义ViewModel。
现在,您可以使用此属性标记控制器或操作,以实现您希望默认拥有的行为。
如果您希望所有方法都采用此行为,只需将AddMvc
行更改为以下内容:
services.AddMvc(config => config.Filters.Add(new ValidateModelAttribute()));
答案 2 :(得分:0)
经过进一步的实验,我找到了答案。
是否需要激活数据验证?
答案:这取决于您的配置服务方法:
不,如果您使用
,则无需激活services.AddMvc();
是的,如果您使用
,则需要激活它services.AddMvcCore()
.AddDataAnnotations(); //this line activates it
这article让我得到答案。