议题
在设计的时候要添加验证以保证表单中输入的内容与数据库和模型设计的类型相符。
解决方案
在.NET 4.0的MVC 3中包含新的命名空间DataAnnotations提供了许多有用的元数据属性。为了验证表单的输入,以下的属性类可以提供多种验证方式:RequireAttribute,RegularExpressionAttribute和DataTypeAttribute。当需要定义必须输入的内容时 ,MVC 3支持开发人员通过改进的ValidationAttribute类对验证进行定义。
讨论
在先前代码优先的秘诀中我们创建Book模型,我们将进行以下更新:
6个输入项中有5个的验证可以通过MVC 3的内置验证方法来定制。但是ISBN的格式需要不同的验证方式 --- 自定义验证方法:
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using MvcApplication4.Validations;
namespace MvcApplication4.Models
{
public class Book
{
public int ID { get; set; }
[Required]
public string Title { get; set; }
[Required]
[IsbnValidation]
public string Isbn { get; set; }
[Required]
public string Summary { get; set; }
[Required]
public string Author { get; set; }
public string Thumbnail { get; set; }
[Range(1, 100)]
public double Price { get; set; }
[DataType(DataType.Date)]
[Required]
public DateTime Published { get; set; }
}
public class BookDBContext : DbContext
{
public DbSet<Book> Books { get; set; }
}
}
在上面这个例子中,由[Require]属性来标识用户必须输入字段。必须要在IsbnValidationAttribute类中添加IsValid属性,以便在操作的时候通知MVC 3调用。为了验证价格,在Price字段上面添加[Range]类,并设置[RegularExpression]属性如下:
[Range(1, 100)]
[RegularExpression(@"(\b[\d\.]*)")]
public double Price { get; set; }
最后,通过定义DataType属性告诉MVC,published成员类型是时间类型。当前IsbnValidation类并不会在验证时候显示任何错误,接下来我们将实现它。
ISBN的有效长度为10至13个字符长度。为了更好的组织代码,将自定义验证代码以及其他验证代码文件放置在单独的文件夹中保存。右键单击该项目,并选择“添加”->“新建文件夹”,并将该文件夹重命名为“Validations”。然后选择“添加”->“类”,将其命名为”IsbnValidationAttribute.cs”,这个类将继承ValidationAttribute类以及重写IsValid方法以验证输入的ISBN内容:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text.RegularExpressions;
namespace MvcApplication4.Validations
{
[AttributeUsage(AttributeTargets.Field |
AttributeTargets.Property, AllowMultiple = false,
Inherited = true)]
public class IsbnValidationAttribute :
System.ComponentModel.DataAnnotations.ValidationAttribute
{
/**
* This class is courtesy:
* http://www.java2s.com/Open-Source/CSharp/
* Inversion-of-Control-Dependency-Injection/Spring.net/
* Spring/Validation/Validators/ISBNValidator.cs.htm
*
* This class is used for demonstration purposes
* of performing an ISBN validation. Should you
* wish to use this in your project, please
* consult the license agreement here:
* http://www.apache.org/licenses/LICENSE-2.0
**/
private static readonly String SEP = "(?:\\-|\\s)";
private static readonly String GROUP = "(\\d{1,5})";
private static readonly String PUBLISHER = "(\\d{1,7})";
private static readonly String TITLE = "(\\d{1,6})";
static readonly String ISBN10_PATTERN =
"^(?:(\\d{9}[0-9X])|(?:" + GROUP + SEP + PUBLISHER +
SEP + TITLE + SEP + "([0-9X])))$";
static readonly String ISBN13_PATTERN =
"^(978|979)(?:(\\d{10})|(?:" + SEP + GROUP + SEP +
PUBLISHER + SEP + TITLE + SEP + "([0-9])))$";
public IsbnValidationAttribute() :
base("Invalid ISBN number")
{
}
public override bool IsValid(object value)
{
// Convert to string and fix up the ISBN
string isbn = value.ToString();
string code = (isbn == null)
? null :
isbn.Trim().Replace("-", "").Replace(" ", "");
// check the length
if ((code == null) || (code.Length < 10
|| code.Length > 13))
{
return false;
}
// validate/reformat using regular expression
Match match;
String pattern;
if (code.Length == 10)
{
pattern = ISBN10_PATTERN;
}
else
{
pattern = ISBN13_PATTERN;
}
match = Regex.Match(code, pattern);
return match.Success && match.Index == 0 &&
match.Length == code.Length;
}
}
}
上面的这个例子是一个C#开源示例包含一个ISBN标准验证程序。IsValid方法会匹配两个验证规则,如果通过就会返回True,否则返回False并请求用户重新输入。
当你访问并提交书籍创建页面的时,就会出现上述错误信息,直到所有输入项都输入了正确的数据。这个检测通过与否要判断ModelState.IsValid属性是否为True。
参考信息