我正在使用Code First方法与实体框架一起创建.NET Core WEB API项目。我在验证来自请求的输入时遇到了麻烦,因为 ModelState验证始终为真。
我的应用程序由3层组成。
DAL中的示例数据模型:
public class Group
{
[Key]
[Required]
public long GroupId { get; set; }
[Required]
public string Name { get; set; }
[Required(AllowEmptyStrings = false)]
public string Description { get; set; }
public DateTime CreationDate { get; set; }
public bool IsActive { get; set; }
}
对应的DTO:
public class GroupDto
{
public long GroupId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
控制器方法:
[HttpPost]
public IActionResult Post([FromBody] GroupDto groupDto)
{
Group group = _mapper.Map<Group>(groupDto);
if (!ModelState.IsValid)
{
return BadRequest();
}
_groupService.Add(group);
groupDto = _mapper.Map<GroupDto>(group);
return Ok(groupDto);
}
据我所知,在当前状态下ModelState.IsValid将始终返回true,因为GroupDto没有通过DataAnnotations完成任何验证。
应如何验证DTO?我想避免在两个地方重复相同的验证。如果应该创建其他自定义DtoValidator,或者我错过了somtething,可以执行这些验证。
答案 0 :(得分:3)
模型状态验证将在传入的模型(在您的情况下为GroupDto)中进行。仅仅因为您最终映射到Group类与验证的工作方式无关。您将需要在DTO中重复验证属性。这确实重复了代码,但是还允许您自定义规则,因为您可能希望也可能不需要DTO中的完全相同的设置。例如,您的主键。对于创建(POST),您不一定希望GroupId成为传递到控制器的必填字段,因为DB可能会自动生成该字段(取决于您的设置)。
如果使用的是ASP.Net Core 2.1或更高版本,则现在还可以将[ApiController]属性应用于控制器类,它将自动应用模型验证规则。这样就无需手动检查ModelState.IsValid。如果模型无效,系统将自动返回400 Bad Request。 (https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-2.2#annotation-with-apicontroller-attribute)
答案 1 :(得分:0)
DTO 和模型是不同的东西,所以应该在两者中都设置 DataAnnotation 属性。 “ModelState.IsValid”检查的主题是您处理的函数的输入。因此,在您的代码中,被检查的模型是 GroupDto。
$timeout = 5; // seconds
$fp = fsockopen($server, $port, $errno, $errstr, 5); // The timeout set here doesn't affect the streaming timeout
if (!$fp) {
echo "$errstr ($errno)<br>\n";
} else {
$urlstring = "GET ".$url." HTTP/1.0\r\n\r\n";
fputs ($fp, $urlstring);
while ($str = trim(fgets($fp, 4096))){
header($str);
}
$start = time();
$now = time();
while ( $now - $start < $timeout ) {
echo fread( $fp, 4096 );
$now = time();
}
fclose($fp);
}
无论如何,为了使控制器中的“模型验证”干净利落,我建议使用自定义的 ValidateModelAttribute,就像这样。
[HttpPost]
public IActionResult Post([FromBody] GroupDto groupDto)
{
Group group = _mapper.Map<Group>(groupDto);
if (!ModelState.IsValid) // this line will check the validation inside GroupDto
然后你可以像这样在控制器上编写验证。
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace MyWeb.App.Filter
{
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting( HttpActionContext actionContext )
{
if( !actionContext.ModelState.IsValid )
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState );
// Path to the error in request content will be sent to the client, so helpful!
}
}
}
}
希望这能回答问题。