我已经得到了我想要使用IDataErrorInfo的接口作为一个简单的地址条目应用在asp.net网站解释 。
它可以独立验证,但不是那么好当一些项目依赖他人物品的伟大工程。 例如,验证邮政编码取决于国家:
private string _PostalCode;
public string PostalCode
{
get
{
return _PostalCode;
}
set
{
switch (_Country)
{
case Countries.USA:
if (!Regex.IsMatch(value, @"^[0-9]{5}$"))
_errors.Add("PostalCode", "Invalid Zip Code");
break;
case Countries.Canada:
if (!Regex.IsMatch(value, @"^([a-z][0-9][a-z]) ?([0-9][a-z][0-9])$", RegexOptions.IgnoreCase))
_errors.Add("PostalCode", "Invalid postal Code");
break;
default:
throw new ArgumentException("Unknown Country");
}
_PostalCode = value;
}
}
所以,你也只能验证邮政编码全国已定之后,但似乎没有控制顺序的方式。
我可以用从IDataErrorInfo的错误字符串,但并不在Html.ValidationMessage显示该字段旁边。
对于更复杂的业务规则验证,而不是类型验证它也许是更好地实现设计模式,例如一个服务层。 您可以检查ModelState中,并添加基于你的逻辑错误。
你可以在这里查看模式罗布Conroys例子
http://www.asp.net/learn/mvc/tutorial-29-cs.aspx
本文对数据注释AY也有益处。
http://www.asp.net/learn/mvc/tutorial-39-cs.aspx
希望这可以帮助。
下面是我找到了超越了简单的数据模型的注释更复杂的验证的最佳解决方案。
我敢肯定,我不是一个人在努力实现IDataErrorInfo
,看到它已经不仅创造了我两种方法来实现。 我想等一下 - 我一定要进去,并从头开始写信自己的自定义程序的一切? 而且 - 如果我有模型层次的东西来验证。 好像你是你自己的,当你决定,除非你想做些什么来使用它像这样或这样从IDataErrorInfo的实现中。
我碰巧有相同问题的提问。 我想,以验证美国邮编,但只有当国家被选为美国。 显然,一个模型级数据的注释也不会有什么好,因为这会不会导致邮政编码,以红色突出显示为错误。 [一类电平数据注解的很好的例子可以在MVC 2示例项目在PropertiesMustMatchAttribute类中找到。
该解决方案很简单:
首先,你需要注册在Global.asax的一个ModelBinder的。 如果你想,但我发现在Global.asax中注册更加灵活,你可以做到这一点作为一个一流水平的[属性]。
private void RegisterModelBinders()
{
ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder();
}
然后创建的模型绑定器类,并编写复杂的验证。 你有充分的访问对象的所有属性。 这将运行任何数据注解已运行后,这样你就可以,如果你想扭转任何验证的默认行为总是很清楚模型的状态属性。
public class AddressModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
// get the address to validate
var address = (Address)bindingContext.Model;
// validate US zipcode
if (address.CountryCode == "US")
{
if (new Regex(@"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).
Match(address.ZipOrPostal ?? "").Success == false)
{
// not a valid zipcode so highlight the zipcode field
var ms = bindingContext.ModelState;
ms.AddModelError(bindingContext.ModelName + ".ZipOrPostal",
"The value " + address.ZipOrPostal + " is not a valid zipcode");
}
}
else {
// we don't care about the rest of the world right now
// so just rely on a [Required] attribute on ZipOrPostal
}
// all other modelbinding attributes such as [Required]
// will be processed as normal
}
}
这样做的好处是,所有现有的验证特性仍然可以工作 - [必需],[为EmailValidator],[MyCustomValidator] - 无论你有。
你可以只添加任何额外的代码到模型绑定和设置场,或模型级的ModelState错误,如你所愿。
请注意,我的Address
是主模型的孩子-在这种情况下CheckoutModel
看起来像这样:
public class CheckoutModel
{
// uses AddressModelBinder
public Address BillingAddress { get; set; }
public Address ShippingAddress { get; set; }
// etc.
}
这就是为什么我要做的bindingContext.ModelName
+ ".ZipOrPostal"
,使模型误差将为‘BillingAddress.ZipOrPostal’和‘ShippingAddress.ZipOrPostal’进行设置。
PS。 从“单元测试类型”的任何意见理解。 我不知道这个单元测试的影响。
关于对字符串错误的评论,IDataErrorInfo的和Html.ValidationMessage,您可以使用与现场级的错误信息显示对象级别:
Html.ValidationMessage("address", "Error")
Html.ValidationMessage("address.PostalCode", "Error")
在控制器中装饰用[装订(前缀=“地址”)]该对象的后处理程序的方法的参数。 在HTML中,命名输入字段这样...
<input id="address_PostalCode" name="address.PostalCode" ... />
我一般不使用HTML佣工。 注意ID和名称的命名约定。