【发布时间】:2009-10-19 09:32:38
【问题描述】:
针对不同操作验证我的模型的最佳做法是什么,例如,创建和删除的不同验证规则?
谢谢!
澄清:我认为这需要澄清一下,因为答案似乎没有解决问题。
例如,
创建人物 验证没有使用姓名、年龄和电子邮件 删除人员 验证 Person 不是 Parent。业务逻辑表明父母不能被淘汰
我如何拥有这两种不同的验证场景?
【问题讨论】:
针对不同操作验证我的模型的最佳做法是什么,例如,创建和删除的不同验证规则?
谢谢!
澄清:我认为这需要澄清一下,因为答案似乎没有解决问题。
例如,
创建人物 验证没有使用姓名、年龄和电子邮件 删除人员 验证 Person 不是 Parent。业务逻辑表明父母不能被淘汰
我如何拥有这两种不同的验证场景?
【问题讨论】:
据我了解,您希望对验证规则进行更多控制。您可以手动添加验证规则,如下所述:MVC 2.0 Client validation exposed 这使您可以完全控制如何组织验证、哪个规则添加到哪个操作等。
【讨论】:
使用 FluentValidation 或 NHibernate Validators 等验证库进行验证。将此代码移动到模型绑定器中,以便在传递模型时自动进行验证。您可以查看以下适用于 FluentValidation 的模型绑定器
public class FluentValidationModelBinder : DefaultModelBinder {
private readonly IValidatorFactory _validatorFactory;
public FluentValidationModelBinder(IValidatorFactory validatorFactory) {
_validatorFactory = validatorFactory;
}
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
var model = bindingContext.Model;
base.OnModelUpdated(controllerContext, bindingContext);
IValidator validator = _validatorFactory.GetValidator(bindingContext.ModelType);
if (validator != null) {
var result = validator.Validate(model);
if (!result.IsValid) {
result.AddToModelState(bindingContext.ModelState, "");
}
}
}
}
【讨论】:
澄清:我认为这需要澄清一下,因为答案似乎没有解决问题。
例如,
创建具有姓名、年龄和电子邮件的人员验证未使用删除人员验证人员不是父母。业务逻辑表明父母不能被淘汰
我如何拥有这两种不同的验证场景?
“封装变化的东西。”
实现此目的的一种方法是使用命令模式,并将您的验证应用于命令而不是实体。这是一个没有使用任何验证框架的简单示例,但思路是一样的。
public class Blub
{
public int BlubId { get; set; }
public string Name { get; set; }
public bool SomeBlockingCondition { get; set; }
}
public class BlubEditController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Rename(int blubId)
{
var ctx = new DataContext();
var blub = ctx.Blubs.Single(o => o.BlubId==blubId);
return ShowRenameForm(blub);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Rename(int blubId, RenameCommand cmd)
{
var ctx = new DataContext();
var blub = ctx.Blubs.Single(o => o.BlubId==blubId);
cmd.Subject = blub;
if (cmd.Validate(ModelState, "cmd."))
{
cmd.Execute();
ctx.SubmitChanges();
return RedirectToAction("Show", new { blubId = blubId });
}
else
{
return ShowRenameForm(blub);
}
}
}
public class RenameCommand
{
public Blub Subject { get; set; }
public string Name { get; set; }
public bool Validate(ModelStateDictionary modelState, string prefix)
{
if (Subject.SomeBlockingCondition)
{
modelState.AddModelError(prefix + "SomeBlockingCondition", "No!");
return false; // Optional shortcut return to prevent further validation.
}
if (String.IsNullOrEmpty(this.Name))
{
modelState.AddModelError(prefix + "Name", "Seriously, no.");
}
return modelState.IsValid;
}
public void Execute()
{
Subject.Name = this.Name;
}
}
【讨论】:
最好使用Validator Toolkit for ASP.NET MVC
此工具包生成客户端和服务器端验证代码。
这是compares different validation techniques and frameworks最近的一篇博文。
如果您使用的是 jQuery,那么 jQuery validation plugin 值得使用。当然,您仍然需要编写自己的服务器端验证(或使用其他框架)。
【讨论】:
如果您使用 ASP.NET MVC 1,您将检查 DataAnnotationsModelBinder 扩展。 System.ComponentModel.DataAnnotations 是非常有用的验证属性框架! 并且 ASP.NET MVC 2 DefaultModebinder 支持它。
http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471
【讨论】:
如果您想使用 ASP.NET MVC 的多个验证框架之一(xVal、数据注释属性等)并且只验证特定操作的模型字段的子集,最简单的解决方案是使用 @ 987654321@属性。
虽然我当然可以想到您可能只想验证模型字段的子集(即在 Create 操作中)的情况,但我想不出您希望验证特定字段的情况字段在两个不同的操作之间完全不同。
这是一个简单的示例,它使用 Person 模型对象和 Data Annotations 验证器属性。 Create 和 Update 操作将针对一组不同的模型字段进行验证。
型号:
public class Person
{
[Required]
Int32 Id { get; set; }
[Required]
String FirstName {get; set;}
[Required]
String LastName {get; set;}
}
控制器操作:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create( [Bind(Exclude = "Id")] Person person )
{
// this action will not perform any validation checks against the Id property of the model
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update( Person person )
{
// this action will perform validation checks against all model properties, including Id
}
在上面的示例中,Create 操作将完全忽略 Person 模型对象的 Id 属性。它不会尝试绑定此属性,也不会尝试对其执行任何验证。由于 Person 在创建时不会有 Id,这正是您想要的。另一方面,Update 操作将针对模型的所有属性进行绑定和验证。
在方法参数上指定Bind 属性这一事实会使代码有点丑陋。但是,如果Exclude 列表变长,您可以随时添加一些额外的换行符和空格来帮助减少丑陋。
【讨论】:
我认为,对于这种情况,只需在DELETE的领域模型(BLL)中编写一些代码来判断是否可以删除某些Person,或者在sql或sp中编写一些代码并返回一个值来指定是否删除完成了。
【讨论】: