我正在设计一个带有MVC,服务和存储库层的分层Web应用程序,但是我无法知道在何处放置验证逻辑,这使得我可以利用内置表单验证的.NET Core (例如ModelStateDictionary
),同时遵循DRY原则。
第一个最明显的方法是使用具有相应数据注释的ViewModel
:
public class VendorViewModel
{
public long Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Address { get; set; }
public DateTime? VerifiedAt { get; set; }
}
然后我的控制器动作看起来像这样
public async Task<IActionResult> Create([FromForm] VendorViewModel model)
{
await AuthorizePolicyAsync(AuthorizationPolicyTypes.Vendor.Create);
if (!ModelState.IsValid) //Validation problems, so re-display the form.
return View(model);
await _vendorservice.CreateVendorAsync(model.Name,model.Phone,model.Email,model.Address,null);
return RedirectToAction(nameof(Index));
}
这很好用,但有几个问题:
model.Address
是有效地址,还包含应用程序知道的城市的,这意味着应该将这种验证移到服务层以保持控制器&#34;瘦&#34;。 第二方法是将所有验证逻辑移至服务层,并将所有数据注释移至实际域对象Vendor
。这样,每个操作都可以基于数据注释验证模型,并且还应用任何更复杂的逻辑,例如使用谷歌地图验证地址,如前所述。但是,我不确定如何以与MVC Controller
相同的方式验证带注释的对象并将字典传回控制器。这个功能似乎特定于MVC,并且会在我的服务层中引入对MVC的依赖,这是不可取的。
无论如何,我可以优雅地将验证逻辑移动到服务层
利用ModelStateDictionary
内置的数据注释和MVC?如何将错误列表返回给控制器?如果发生任何验证错误,是否抛出异常并将其捕获到控制器中?
我已经看到了几个提出类似问题的问题,但我对任何答案都不满意。其他答案似乎涉及手动编写验证逻辑而不利用数据注释。这是我应该诉诸的吗?
答案 0 :(得分:0)
您可以创建自己的自定义验证属性,以及开箱即用的属性,例如Required,Range,StringLength等。 我将在下面提供一个例子:
public class ValidateAddressAttribute : Attribute, IModelValidator
{
public bool IsRequired => true;
public string ErrorMessage { get; set; } = "Address is not valid";
public IEnumerable<ModelValidationResult>Validate(ModelValidationContext context)
{
List<ModelValidationResult> validationResults = new List<ModelValidationResult>();
string address = context.Model as string;
if(!IsAddressValid(address))
{
validationResults.Add(new ModelValidationResult("", ErrorMessage));
}
return validationResults;
}
private bool IsAddressValid(string address)
{
bool isAddressValid;
//set isAddressValid to true or false based on your validation logic
return isAddressValid;
}
}
您现在可以在地址属性中应用此属性,如下所示:
[Required]
[ValidateAddress(ErrorMessage="Invalid Address")]
public string Address { get; set; }