ASP.NET MVC 模型绑定的 6 个建议
2013-12-19 10:06
501 查看
ASP.NET MVC 中的 Model Binding 使用起来非常简单。你的 Action 方法需要数据,在传入的 HTTP 请求中携带着你需要的数据,数据可以在请求的表单数据中,还可能在你的 URL 地址本身中。通过 DefaultModelBinder,可以神奇地将表单中的数据和路由中的数据转换到对象中。Model Binder 使得你的控制器代码可以干净地从请求以及关联的环境中分离出来。
这里有一些关于在 MVC 项目中更好使用 Model Binding 的建议。
如果你的 Action 像下面这样:
就不对了。这些属性使得你的 Action 很难读而且更难以测试,Model Binder 可以帮你从 Request 和 HttpContext 中摆脱出来。比如,你可以使用 FormCollection 类型的参数来代替上面的代码:
使用 FormCollection 你可以不必再深入到 Request 对象,这样,有时候你就可以使用低层次的控制了。但是,如果你的数据来自 Request.Form,或者 URL 请求参数,你可以通过 Model Binding 来完成它的魔术。
在这个例子中,Model Binder 将会帮你创建 newRecipe 对象,并且使用从 Request 中获得获得的数据来填充它,真的是魔术。有许多的途径允许你定制绑定的处理过程,使用白名单,黑名单,前缀,以及接口,更多的控制还允许你通过 UpdateModel 和 TryUpdateModel 方法进行,只是要注意无意的绑定。看一看 Justin Etheredge 的文章 Think
Before You Bind.
在 MVC 中,Model Binding 也是一个扩展点。如果默认的绑定不合适的话,你可以提供一个自定义的 Model Binder,实现自定义的 Model Binder 你需要实现接口 IModelBinder,这是仅有的一个方法,有多难吗?
一旦你进入Model Binding,实际上,你将会发现这个简单的 IModelBinder 接口并没有完全描述在框架中的默认契约和负作用。如果你退回一步看一看,就会发现 Model Binder, ModelState 以及 HtmlHelper。
Scott Hanselman 在他的 “Splitting DateTime – Unit Testing ASP.NET MVC Custom
Model Binders” 中给出了一个并不是演示版的 Model Binder,一个我需要提出来的细节是 Scott 的 DateTime 分离器仍然没有通过 Request.Form 来绑定,在 GetA<T> 方法中,你将会看到 Scott 使用了上下文对象的 ValueProvider 属性来获得数据,ValueProvier 表示混合了表单数据,路由数据,以及请求参数数据的数据。Scott 的例子非常棒,但是,少了一个细节:绑定中的错误。
如果默认的模型绑定器在将数据绑定到你的对象上时出现了问题,它会将错误信息和错误的数据压入到 ModelState 中,你可以检查 ModelState.IsValid 来检查绑定中的问题,使用 ModelState.AddModelError 方法可以注入你自己的错误信息。
如果你看看 Scott 文章的回应,你会看到 Sebastien Crocquesel’s 对这个问题的补丁。如果转换失败,Sebastien 的代码将会使用 ModelState.AddModelError 方法来表示错误。Controller 和 View 都会使用
ModelState 来检查绑定的问题。Controller 需要检查 ModelState,以便在将数据保存到数据库之前检查错误,而 View 需要通过 ModelState 来为用户提供验证的回应。需要注意的一点是 HtmlHelper ,你需要同时提供一个值,通过 ModelState.SetModelValue ,并且提供错误信息,通过 AddModelError,否则你将会得到一个运行时的空引用异常,下面的代码演示了这个问题。
上面的代码创建了一个模型的错误信息,但是没有提供值。也有其他的问题,但是,如果你像下面一场呈现视图,那么,就会得到一个异常。
纵然你为 Model.Name 提供了一个值,HtmlHelper 也会发现错误,然后显示试图的值。如果你没有提供值,就会看到一个空引用异常。
如果你决定实现一个自定义的 Model Binder,你可能希望通过从 DefaultModelBinder 继承来减少部分工作量,其实,最终你会发现不能通过继承 DefaultModelBinder 来达到你的目的。例如,假如你希望通过自定义的 ModelBinder 来创建某些对象,DefaultModelBinder 将会使用 Activator.CreateInstance 和 Model 的默认构造函数来创建对象,如果你的模型没有提供默认的构造函数,你可以重写 CreateModel 方法来解决这个问题。
Jimmy 有一篇关于使用 DefaultModelBinder 的派生类的帖子 “A Better Model Binder”.
Brad Wilson 在他的文章 DataAnnotations and ASP.NET MVC 中,完美地演示了一切。
我建议你仔细读一下 Brad Wilson 的文章,如果你想快一点,这里总结了一下。
.NET 3.5 SP1 带来了 System.ComponentModel.DataAnnotations 程序集,通过数据的注解和 DataAnnotationModelBinder,你可以处理大部分的服务器端验证问题,只需要简单地标注你的模型
绑定是从环境中获得数据,然后赋予模型对象的过程,验证是检查模型对象的数据,确认符合我们的期望。这是完全不同的操作,但是模型绑定模糊了他们的区别。如果你希望在 Model Binder 中一起完成这两步工作,是可以的,这需要准确地知道 DataAnnotationsModelBinder 做了什么,你可以看这几个例子。实际上,经常被忽略的一点是 DefaultModelBinder 如何分离绑定和验证步骤。如果只是简单属性的验证,所有你要做的就是重写 DefaultModelBinder 的 OnProperValidating
方法。
下面的几篇文章可以参考一下:
Automatic Model
Validation with ASP.NET MVC, xVal, Castle, and a Custom Binder
Enterprise
Library Validation Application Block with MVC Binders
前面我说过:Model Binder 可以帮你从 Request 和 HttpContext 中摆脱出来。从更加广泛的角度来说,并没有限制数据的来源,请求上下文中包含丰富的客户端信息。Scott Hanselman 的另外一篇文章演示了将用户的标识绑定到模型上。
Model Binding 是美妙的魔术,所以,尽可能使用内置的奇妙功能。
这里有一些关于在 MVC 项目中更好使用 Model Binding 的建议。
Tip#1:最好使用 Model Binding 而不是 Request.Form
如果你的 Action 像下面这样:Before You Bind.
Tip#2 定制 Model Binder
在 MVC 中,Model Binding 也是一个扩展点。如果默认的绑定不合适的话,你可以提供一个自定义的 Model Binder,实现自定义的 Model Binder 你需要实现接口 IModelBinder,这是仅有的一个方法,有多难吗?Scott Hanselman 在他的 “Splitting DateTime – Unit Testing ASP.NET MVC Custom
Model Binders” 中给出了一个并不是演示版的 Model Binder,一个我需要提出来的细节是 Scott 的 DateTime 分离器仍然没有通过 Request.Form 来绑定,在 GetA<T> 方法中,你将会看到 Scott 使用了上下文对象的 ValueProvider 属性来获得数据,ValueProvier 表示混合了表单数据,路由数据,以及请求参数数据的数据。Scott 的例子非常棒,但是,少了一个细节:绑定中的错误。
如果默认的模型绑定器在将数据绑定到你的对象上时出现了问题,它会将错误信息和错误的数据压入到 ModelState 中,你可以检查 ModelState.IsValid 来检查绑定中的问题,使用 ModelState.AddModelError 方法可以注入你自己的错误信息。
如果你看看 Scott 文章的回应,你会看到 Sebastien Crocquesel’s 对这个问题的补丁。如果转换失败,Sebastien 的代码将会使用 ModelState.AddModelError 方法来表示错误。Controller 和 View 都会使用
ModelState 来检查绑定的问题。Controller 需要检查 ModelState,以便在将数据保存到数据库之前检查错误,而 View 需要通过 ModelState 来为用户提供验证的回应。需要注意的一点是 HtmlHelper ,你需要同时提供一个值,通过 ModelState.SetModelValue ,并且提供错误信息,通过 AddModelError,否则你将会得到一个运行时的空引用异常,下面的代码演示了这个问题。
Tip#3 通过继承来自定义 Model Binding
如果你决定实现一个自定义的 Model Binder,你可能希望通过从 DefaultModelBinder 继承来减少部分工作量,其实,最终你会发现不能通过继承 DefaultModelBinder 来达到你的目的。例如,假如你希望通过自定义的 ModelBinder 来创建某些对象,DefaultModelBinder 将会使用 Activator.CreateInstance 和 Model 的默认构造函数来创建对象,如果你的模型没有提供默认的构造函数,你可以重写 CreateModel 方法来解决这个问题。Jimmy 有一篇关于使用 DefaultModelBinder 的派生类的帖子 “A Better Model Binder”.
Tip#4 使用注解来完成验证
Brad Wilson 在他的文章 DataAnnotations and ASP.NET MVC 中,完美地演示了一切。我建议你仔细读一下 Brad Wilson 的文章,如果你想快一点,这里总结了一下。
.NET 3.5 SP1 带来了 System.ComponentModel.DataAnnotations 程序集,通过数据的注解和 DataAnnotationModelBinder,你可以处理大部分的服务器端验证问题,只需要简单地标注你的模型
Tip#5 绑定和验证是两个步骤
绑定是从环境中获得数据,然后赋予模型对象的过程,验证是检查模型对象的数据,确认符合我们的期望。这是完全不同的操作,但是模型绑定模糊了他们的区别。如果你希望在 Model Binder 中一起完成这两步工作,是可以的,这需要准确地知道 DataAnnotationsModelBinder 做了什么,你可以看这几个例子。实际上,经常被忽略的一点是 DefaultModelBinder 如何分离绑定和验证步骤。如果只是简单属性的验证,所有你要做的就是重写 DefaultModelBinder 的 OnProperValidating方法。
下面的几篇文章可以参考一下:
Automatic Model
Validation with ASP.NET MVC, xVal, Castle, and a Custom Binder
Enterprise
Library Validation Application Block with MVC Binders
Tip#6 关于绑定的内容
前面我说过:Model Binder 可以帮你从 Request 和 HttpContext 中摆脱出来。从更加广泛的角度来说,并没有限制数据的来源,请求上下文中包含丰富的客户端信息。Scott Hanselman 的另外一篇文章演示了将用户的标识绑定到模型上。
综上所述
Model Binding 是美妙的魔术,所以,尽可能使用内置的奇妙功能。
相关文章推荐
- ASP.NET MVC模型绑定的6个建议
- ASP.NET MVC 模型绑定的 6 个建议
- ASP.NET MVC模型绑定的6个建议
- ASP.NET MVC 模型绑定的 6 个建议
- ASP.NET MVC模型绑定的6个建议,徐汇区网站设计
- ASP.NET MVC学习之模型绑定(2)
- Asp.Net MVC模型绑定
- ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)
- [转] ASP.NET MVC 模型绑定的功能和问题
- ASP.NET MVC中 Jquery AJAX 获取数据利用MVC模型绑定实现输出
- asp.net mvc 自定义模型绑定
- ASP.NET MVC保持表单数据状态的方法:input辅助器+模型绑定
- ASP.NET MVC 4 (九) 模型绑定
- Asp.net Mvc 中的模型绑定
- asp.netMVC中的自动绑定模型测试小结
- ASP.NET MVC学习三-数据传递之模型绑定
- ASP.Net MVC 模型绑定
- The DefaultModelBinder in ASP.NET MVC -ASP.NET MVC的默认模型绑定器
- asp.net mvc 中的模型绑定
- ASP.NET MVC学习之模型绑定(1)