ASP.NET MVC 模型绑定和数据注解
MVC 模型绑定和数据注解简介。
引言
ASP.NET MVC 将 Web 应用程序分为三个主要组件:模型、视图和控制器。MVC 框架映射 URL 并将请求传递给控制器。它还提供模型绑定,用于从请求中检索数据,填充控制器操作参数,并处理通常与 ASP.NET 请求数据交互相关的属性映射和类型转换。
在本文中,我将讨论模型绑定和使用数据注解进行数据验证。本文旨在重点介绍开发 MVC 应用程序时开发者可能遇到的 MVC 中模型绑定和注解的一些细节。
模型绑定
在讨论模型绑定之前,让我们看看我们通常如何检索用户输入数据。以下示例显示了我们如何从请求对象中检索数据。
public ActionResult Edit() { int id = Int32.Parse(Request["StudentID"]); string studentName = Request["StudentName"]; DateTime birthday = DateTime.Parse(Request["BirthDay"]); var student = new Student() { StudentID = id, StudentName = studentName, BirthDay = birthday }; ... }
在控制器中,我们从请求对象中检索用户输入。我们需要进行数据类型转换,并将输入值映射到属性。我们还需要进行数据验证,例如必填项或检查数据格式。控制器中需要编写大量代码。ASP.NET MVC 框架提供了模型绑定,极大地简化了此过程。框架检索数据,将数据映射到对象属性,验证数据,并将模型对象作为参数传递给控制器。以下示例显示了我们如何使用模型绑定处理用户输入。
public ActionResult Edit(Student student) { if (ModelState.IsValid) { // call update return View("Index"); } // display error return View(); }
在控制器中,模型对象由模型绑定器创建并作为参数传递给控制器。我们通过调用 ModelState.IsValid
来检查数据是否有效。如果数据有效,我们可以继续,否则我们将向用户返回带有错误消息的视图。模型绑定器处理所有属性映射和验证。
默认模型绑定器
ASP.NET MVC 框架提供了一个非常强大的默认模型绑定器,它可以绑定大多数数据类型,从基本类型、数组、集合到复杂对象。以下详细解释了绑定。
绑定到基本值
默认模型绑定器可以将请求绑定到控制器参数的基本类型。在以下示例中,我们从请求中检索三个值。
public ActionResult Edit(int StudentID, string StudentName, DateTime BirthDay) { return View(); }
绑定到集合
默认模型绑定器可以将基本数据类型的集合绑定。集合可以是简单的数组,也可以是 IEnumerable<T>
、ICollection<T>
和 IList<T>
等集合。IDictionary<TKey, TValue>
类型也可以被绑定。对于集合绑定,控制器参数可能如下所示:
public ActionResult Edit(int[] id) { return View(); } public ActionResult Edit(IList<int> id) { return View(); }
要将上述参数传递给控制器,我们需要在输入名称后附加索引以将输入标记为集合。我们需要在 HTML 表单中有如下所示的 HTML 输入:
<input type="text" name="id[0]" value="1" /> <input type="text" name="id[1]" value="2" /> <input type="text" name="id[2]" value="3" />
绑定到简单对象
默认模型绑定器可以绑定到像 Student 这样的简单对象。Student 类具有一些基本数据类型属性,它可能如下所示:
public class Student { public int StudentID { get; set; } public string StudentName { get; set; } }
模型绑定器可以将请求数据绑定到 Student 对象并将其作为参数传递给控制器。
public ActionResult Edit(Student student) { ... }
要将 Student 对象传递给控制器,我们需要像下面这样在表单中使用 HTML 输入:
<input type="text" name="StudentID" value="1" /> <input type="text" name="StudentName" value="alex" />
绑定到对象集合
默认模型绑定器可以像绑定基本数据类型一样绑定对象集合。控制器可能具有如下所示的签名:
public ActionResult Edit(IList<Student> student) { ... }
HTML 输入可能如下所示:
<input type="text" name="student[0].StudentID" value="1" /> <input type="text" name="student[0].StudentName" value="alex" /> <input type="text" name="student[1].StudentID" value="2" /> <input type="text" name="student[1].StudentName" value="joe" />
要绑定到字典,控制器可能具有如下所示的签名:
public ActionResult Edit(IDictionary<string, Student> student) { ... }
HTML 输入可能如下所示:
<input type="text" name="student[0].Key" value="1" /> <input type="text" name="student[0].StudentID" value="1" /> <input type="text" name="student[0].StudentName" value="alex" /> <input type="text" name="student[1].Key" value="2" /> <input type="text" name="student[1].StudentID" value="2" /> <input type="text" name="student[1].StudentName" value="joe" />
绑定到复杂对象
在之前的 Student 示例中,对象只有一个两个简单属性,但我们可以向其中添加其他对象类型,形成一个复杂的对象图。默认模型绑定器可以递归遍历整个复杂对象图并填充嵌套属性值。例如,我们有两个类:
public class Student { public int StudentID { get; set; } public string StudentName { get; set; } public Phone ContactPhone { get; set; } } public class Phone { public string PhoneNumber { get; set; } }
控制器可能具有如下所示的签名:
public ActionResult Edit(Student student) { ... }
要绑定嵌套属性,我们需要使用点表示法来指定复杂类型。格式为 [ParentProperty].[Property]。HTML 输入可能如下所示:
<input type="text" name="StudentID" value="1" /> <input type="text" name="StudentName" value="alex" /> <input type="text" name="ContactPhone.PhoneNumber" value="123-000-0000" />
绑定属性
我们可以添加绑定属性来指示模型绑定器何时绑定属性以及何时排除属性。在以下示例中,我们在绑定时排除 StudentID,在绑定时包含 StudentName。
public ActionResult Create([Bind(Exclude="StudentID", Include="StudentName")]Student student) { ... }
自定义模型绑定器
默认模型绑定器非常强大,可以绑定大多数数据类型。您不需要编写自己的绑定器。如果您确实想自己进行绑定,可以实现 IModelBinder
接口或派生自 DefaultModelBinder
。以下示例展示了如何通过实现 IModelBinder
接口来绑定您的自定义对象。
public class ProductModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var product = new Product() { productID = Int32.Parse(bindingContext.ValueProvider.GetValue("productID").AttemptedValue), productName = bindingContext.ValueProvider.GetValue("productName").AttemptedValue }; return product; } }
创建绑定器后,需要注册该绑定器。在 Application_Start()
中,您需要以下代码来为您的自定义对象类型注册绑定器。
ModelBinders.Binders.Add(typeof(Product), new ProductModelBinder());
Razor 视图引擎
到目前为止,我们已经讨论了 HTML 表单格式和数据绑定,但是我们如何从视图生成 HTML 呢?要生成上述 HTML 输入,我们需要编写 MVC 视图脚本来实现。我将以 Razor 视图引擎为例。
集合视图
还记得我们上面有关于简单集合的 HTML 输入吗?
<input type="text" name="id[0]" value="1" />
在视图中,我们需要调用 HTML 帮助器函数来渲染模型。我写了一个自定义的扩展方法。扩展方法的源代码包含在下载的 zip 文件中,您可以根据需要进行修改。要渲染 HTML 输入,我们在下面的“id.cshtml”视图文件中调用扩展方法 EditorForCollection
。
id.cshtml: @Html.EditorForCollection(model => Model, "id")
在上面的示例中,我们将视图模型和变量名传递给 EditorForCollection
。帮助器函数将处理 HTML 表单中的索引名称。
对象集合视图
对于对象集合,我们可以调用相同的 HTML 帮助器函数来渲染模型。
studentlist.cshtml: @Html.EditorForCollection(model => Model, "student")
复杂对象视图
当我们在 Student 类中添加 Phone 类时,我们使用了一个嵌套对象作为其属性。我们需要使用点表示法来指定嵌套关系。我们需要为每个对象使用模板,并为每个嵌套对象调用 EditorFor
。
Edit.cshtml: @Html.EditorForModel() Student.cshtml: @Html.TextBoxFor(m => m.StudentID) @Html.TextBoxFor(m => m.StudentName) @Html.EditorFor(m => m.ContactPhone) Phone.cshtml: @Html.TextBoxFor(m => m.PhoneNumber)
在上面的示例中,Student
和 Phone
是视图模板。我们为嵌套属性调用 EditorFor
,它将使用点表示法来格式化 HTML。
嵌套对象集合视图
当一个学生有多个电话号码时,我们需要使用集合对象作为其属性,如下例所示:
public class Student { public int StudentID { get; set; } public string StudentName { get; set; } public IList<Phone> ContactPhone { get; set; } }
我们可以使用上面的相同视图,并为嵌套集合属性调用 EditorFor
。
模型数据注解
MVC 框架不仅提供模型绑定器来简化从请求中检索数据,还提供了丰富的支持来使用数据注解来描述模型以进行数据验证和视觉提示。
数据验证
以下示例是常用数据验证的注解。
[Required] public int ID { get; set; } [StringLength(50, MinimumLength = 2)] public string name { get; set; } [Range(15, 100)] public int age { get; set; }
数据类型
数据类型注解可用于指定用于验证的数据类型。在渲染过程中,这些信息也可能用作 UI 提示。
[Url] public string url { get; set; } [Phone] public string phone { get; set; } [DataType(DataType.Date)] public DateTime updatedate { get; set; } [DataType(DataType.PhoneNumber)] public string phone { get; set; }
以下是常用数据类型列表:
Type Description ---------------------------------------------------------------------------------- DateTime Represents an instant in time, expressed as a date and time of day. Date Represents a date value. Time Represents a time value. PhoneNumber Represents a phone number value. Currency Represents a currency value. EmailAddress Represents an e-mail address. Password Represent a password value. Url Represents a URL value. CreditCard Represents a credit card number. PostalCode Represents a postal code.
UI 提示
以下示例是常用显示 UI 提示的注解。
[Display(Name = "Student ID")] public int ID { get; set; } [DisplayFormat(DataFormatString = "{0:d}")] public DateTime myDate { get; set; } [UIHint("CustomDateTime")] // use template to display date public DateTime updateDate { get; set; }
摘要
我已经讨论了 MVC 中模型绑定和数据验证的一些细节。请投票和提出您的建议。希望您喜欢这篇文章。