ASP.NET MVC 模型绑定 - 第 1 部分






4.45/5 (21投票s)
本文档将使读者详细了解 ASP.NET MVC 模型绑定是如何工作的。
引言
ASP.NET MVC 拥有许多出色的功能。我一直在玩弄 ASP.NET MVC,并在模型绑定方面遇到了一些有趣的事情。在这里,我将整理我所有的发现,并用一个简单的例子进行解释。我相信这可以为那些想了解 ASP.NET MVC 模型绑定究竟是如何工作的开发者节省大量时间。
在 ASP.NET MVC 中,模型绑定是将 HTTP 请求数据直接映射到Action
方法参数和 .NET 对象(模型)。
使用代码
由于内容较多,我将把它分成几部分。在本部分中,我将介绍 ASP.NET MVC 对象模型绑定、使用查询字符串参数进行参数绑定,以及使用 `Bind` 属性控制模型绑定。
代码结构如下:
为了简化,并更专注于模型绑定,我将使用一个简单的例子,其中包含一个 `Employee` 模型,一个 `EmployeeController` 控制器,以及两个视图 `EmployeeView1` 和 `EmployeeView2`。
运行上述代码时,它会显示员工添加/编辑页面(添加/编辑到数据库不在本文档的范围内),`EmployeeView1` 视图,如下所示:
'使用查询字符串' 链接用于演示通过查询字符串参数进行模型绑定,'控制模型绑定' 链接用于演示如何控制模型绑定。控制模型绑定可以控制哪些模型属性可以与传入的 HTTP 请求进行绑定。
我使用了 VS 2008 SP1 和 ASP.NET MVC 2 来构建这个示例,建议使用相同的版本。
模型绑定就是这样工作的,例如,考虑以下请求:
POST: Route Values, Query String Parameters
路由值决定了控制器,Action 方法负责处理请求,而查询字符串参数基本上映射到 Action 方法参数,这一点将在下面详细解释。这是 `Employee` 模型:
public class Employee
{
[DisplayName("Employee ID")]
[Required(ErrorMessage = "ID Required")]
public int EmpId { get; set; }
[DisplayName("Employee Name")]
[Required]
public string EmpName { get; set; }
[DisplayName("Designation")]
[Required]
public string EmpDesignation { get; set; }
[DisplayName("Department")]
[Required]
public string EmpDepartment { get; set; }
[DisplayName("Salary")]
[Required]
public float EmpSalary { get; set; }
}
上述模型使用了数据注解来处理简单的验证。在本文档的编写过程中,我们不会过多讨论验证。
绑定方式 1:查询字符串参数
查询字符串参数可以直接映射到 Action 方法参数。考虑以下与示例中的 Action 方法对应的请求:
EmployeeController.cs
-------------------------
public ActionResult UpdateQueryString(int EmpId, string EmpName,
string EmpDepartment, string EmpDesignation)
{
return View("EmployeeView1");
}
上述请求将每个 HTTP 查询字符串参数 `EmpId`、`EmpName`、`EmpDepartment`、`EmpDesignation` 直接分别映射到 Action 方法参数,并将上述 `EmployeeModel` 更新为包含这些值。为了观察这种行为,您可以设置附加的示例源代码,在 Visual Studio 中运行应用程序,然后点击 '使用查询字符串' 链接。我们将在视图页面上看到更新的字段。请看下面的快照。
我们可以使用 `HtmlHelper` 方法来生成上述 HTTP 请求,如下所示。更多信息请参见提供的便捷示例。
<%= Html.ActionLink("Using Query Strings", "UpdateQueryString",
new { EmpId = 1, EmpName = "Nick", EmpDepartment = "IT", EmpDesignation = "Director" })%>
绑定方式 2:对象绑定
我们大多数时候在 Action 方法中都会看到这种绑定。从 HTTP 请求中,值会在后台映射到模型属性,为了使其正常工作,我们需要遵循一些通用规则。例如,考虑以下代码:
[HttpPost]
public ActionResult Update(Employee employee )
{
if (!this.ModelState.IsValid)
ModelState.AddModelError("Employee", "Model is Not Valid");
return View("EmployeeView1");
}
而视图页面包含以下强类型字段渲染方式。例如:
<%= Html.TextBoxFor(model => model.EmpId) %>
上面的代码会自动将文本框中输入的强类型 'EmpId
' 绑定到模型的 `EmpId`(employee),并在提交表单时将其发送到 `Action` 方法。考虑下面的行,而不是上面强类型的方法,我们可以考虑使用下面的方法:
<%= Html.TextBox("employee.EmpId")%>
参数名和属性名组合会从 HTTP 输入中提取值。上述方法遵循 `prefix.PropertyName` 标准。通常,如果我们不指定 `prefix`,它将是 Action 参数名。在上面的例子中,`employee` 是 Action 方法的参数。在 `EmpId` 文本框中输入的值将映射到模型的 `EmpId` 属性。
如果我们使用 `Bind` 属性为 Action 方法指定前缀,如下所示:
[HttpPost]
public ActionResult UsingPrefix([Bind(Prefix = "emp")]Employee employee)
{
if (!this.ModelState.IsValid)
ModelState.AddModelError("Employee", "Employee Not Valid");
return View("EmployeeView2");
}
那么视图页面中的 `Helper` 方法应该如下所示:
<%= Html.TextBox("emp.EmpId")%>
点击提交按钮以观察对象模型绑定。
控制模型绑定
有时,可能不需要在视图中显示所有字段,但模型包含的属性多于视图显示的。这可能成为注入攻击的潜在目标。为了避免这种情况,我们可以使用 `Bind` 属性从视图控制模型绑定。
public ActionResult BindInclude
([Bind(Include = "EmpId,EmpName", Exclude = "EmpSalary")] Employee employee)
{
return View("EmployeeView1");
}
使用 `Bind` 属性,我们可以使用 **Include** 参数名白名单列出模型属性,使用 **Exclude** 参数名黑名单列出模型属性。在上面的代码中,只有来自 HTTP 请求的 `EmpID` 和 `EmpName` 输入将被映射到 employee 模型,如果这导致了由于设置的验证而产生的无效模型状态,那么相应的验证将自动触发。我将在下一部分介绍集合绑定、集合绑定对象等,以及如何进行手动模型绑定。我相信这篇阅读文章可以为那些正在寻找模型绑定解决方案的读者节省大量时间。
免责声明
本文档使用了一个示例,该示例不适用于直接生产部署。它旨在让读者了解模型绑定是如何工作的,并在实现模型绑定时遵循必要的最佳实践是每个人的责任。