.NET MVC学习之模型绑定
ASP.NET MVC学习之模型绑定(2)
3.手工调用模型绑定
很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了很多过程中的控制,所以我们就需要使用手工的方式进行绑定。下面我们通过一个例子来说明,首先打开Views/Home/Index.cshtml页面,并输入如下代码:

1 @{
2 ViewBag.Title = "Index";
3 }
4
5 @if (TempData.ContainsKey("msg"))
6 {
7 <h1>
8 @TempData["msg"].ToString()
9 </h1>
10 }
11
12 @using (Html.BeginForm())
13 {
14 <input type="text" name="id" />
15 <input type="submit" value="submit" />
16 }

接着打开HomeController并写入如下代码(关于ActionName可以点击这进行参考):

1 namespace MvcStudy.Controllers
2 {
3 public class HomeController : Controller
4 {
5 private class TestA
6 {
7 public String id { get; set; }
8 }
9
10 public ActionResult Index()
11 {
12 return View();
13 }
14
15 [HttpPost]
16 [ActionName("Index")]
17 public ActionResult IndexPost()
18 {
19 TestA ta = new TestA();
20 UpdateModel(ta);
21 TempData["msg"] = ta.id;
22 return View();
23 }
24 }
25 }

这里我们通过UpdateModel进行手动绑定,最终的结果和采用形参的方式相同,读者可以进行测试可以发现输入的值都显示了,但是读者一定会奇怪,因为TestA中的id不仅仅存在于表单,同时还存在与RouteData中以及查询字符串中,我们可以用?id=123来测试这个页面可以发现并不会修改最终结果,而通过手动调用模型绑定的优点之一就是我们可以控制数据来源,比如我们修改HomeController代码如下所示:

1 [HttpPost]
2 [ActionName("Index")]
3 public ActionResult IndexPost()
4 {
5 TestA ta = new TestA();
6 UpdateModel(ta,new FormValueProvider(ControllerContext));
7 TempData["msg"] = ta.id;
8 return View();
9 }

这里我们可以发现我们给UpdateModel传递了第二个参数,FormValueProvider这表示数据源只能来自于表单中,同样我们还可以修改成RouteDataValueProvider或者QueryStringValueProvider,具体的效果读者你自行替换之后,输入http://localhost:1201/Home/Index/123?id=asdsad测试,可以看看最后显示的内容是不是来自于我们指定的来源。再使用形参的方式中我们有时会遇到http流中不存在我们需要的值,并且这个形参的类型不能为null,或者我们不希望它为null,这个时候就会出现异常或者赋值为null,而通过UpdateModel则可以通过try…catch…的形式捕获InvalidOperationException异常从而手动处理,如果读者不希望通过这种方式也可以像下面这种形式来处理:

1 if (TryUpdateModel(ta, new QueryStringValueProvider(ControllerContext)))
2 {
3 //正确时的操作
4 }
5 else
6 {
7 //异常时的操作
8 }

这样我们只要通过if判断即可。
4.自定义值提供器
通过上面的我们发现ASP.NET MVC自带的模型绑定器已经提供了很多我们所需要的功能,但是有时候我们想某些值不是来自于http流中而是我们自己来填充的,那么这节知识会让你感兴趣,因为下面我们将要自定义一个值提供器来完成我们的需求。首先介绍需要用的接口和类,首先是IValueProvider接口:
namespace System.Web.Mvc
{
// 摘要:
// 定义 ASP.NET MVC 中的值提供程序所需的方法。
public interface IValueProvider
{
// 摘要:
// 确定集合是否包含指定的前缀。
//
// 参数:
// prefix:
// 要搜索的前缀。
//
// 返回结果:
// 如果集合包含指定的前缀,则为 true;否则为 false。
bool ContainsPrefix(string prefix);
//
// 摘要:
// 使用指定键来检索值对象。
//
// 参数:
// key:
// 要检索的值对象的键。
//
// 返回结果:
// 指定的键的值对象。
ValueProviderResult GetValue(string key);
}
}
其中ContainsPrefix用来判断这个值的前缀是不是我们能够处理的(因为ASP.NET MVC其实自带了很多这种值提供器,最后会通过循环调用的方式调用这些提供器,直到有一个返回值。)然后就是GetValue方法就是返回对应的值了,当然光有这个还不够,还需要一个工厂去创建它,以提供调用,这个类就是ValueProviderFactory,而我们仅仅只需要实现GetValueProvider方法即可,其实就是new一个值提供器并返回,当然你也可以通过这个方法的ControllerContext从而有选择性的返回一个值提供器,下面我们简单的举一个例子来处理ns。
首先我们创建一个Provider文件夹,然后新建一个NSValueProvider类并在文件中写入如下代码:

1 namespace MvcStudy.Provider
2 {
3 public class NSValueProvider : IValueProvider
4 {
5
6 public bool ContainsPrefix(string prefix)
7 {
8 return String.Compare("ns", prefix, true) == 0;
9 }
10
11 public ValueProviderResult GetValue(string key)
12 {
13 if (ContainsPrefix(key))
14 {
15 return new ValueProviderResult("from ns", null, CultureInfo.InvariantCulture);
16 }
17 return null;
18 }
19 }
20
21 public class NSValueProviderFactory : ValueProviderFactory
22 {
23 public override IValueProvider GetValueProvider(ControllerContext controllerContext)
24 {
25 return new NSValueProvider();
26 }
27 }
28 }

最后打开Global.asax将它注册:
1 ValueProviderFactories.Factories.Insert(0, new NSValueProviderFactory());
最后我们需要修改HomeController以便能够看到结果:
1 public ActionResult Index(string ns)
2 {
3 TempData["msg"] = ns;
4 return View();
5 }
重新编译之后刷新页面我们就可以看到如下的结果:

这样我们就完成了一个值提供器了,看到这个读者一定会想模型提供器怎么去自定义呢,其实模型绑定器就是依靠这些值提供器完成的,大家想想就可以明白了。
5.模型绑定器
模型绑定器跟值提供器很相似,只是需要做的工作比较多,因为你要负责将一个类的属性填充,所以比较麻烦。下面是需要实现的接口IModelBinder:

1 namespace System.Web.Mvc
2 {
3 // 摘要:
4 // 定义模型联编程序所需的方法。
5 public interface IModelBinder
6 {
7 // 摘要:
8 // 使用指定的控制器上下文和绑定上下文将模型绑定到一个值。
9 //
10 // 参数:
11 // controllerContext:
12 // 控制器上下文。
13 //
14 // bindingContext:
15 // 绑定上下文。
16 //
17 // 返回结果:
18 // 绑定值。
19 object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
20 }
21 }

这里重点是bindingContext参数,里面包含了很多绑定所需要的值和方法,下面我们举一个简单的例子,就是自定义一个模型绑定器负责绑定如下类:
1 public class TestA
2 {
3 public String id { get; set; }
4 }
同时还要规定只能通过name为ns.id获取值,并不会根据参数的名称去获取,下面就是我们实现接口的代码:

1 namespace MvcStudy.Provider
2 {
3 public class NSModelBinder : IModelBinder
4 {
5
6 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
7 {
8 TestA a = (TestA)bindingContext.Model ?? new TestA();
9 bool isHave = bindingContext.ValueProvider.ContainsPrefix("ns.id");
10 if (isHave)
11 {
12 a.id = bindingContext.ValueProvider.GetValue("ns.id").AttemptedValue;
13 }
14 else
15 {
16 a.id = "asd";
17 }
18 return a;
19 }
20 }
21 }

最后一步当然还是需要注册(Global.asax):
1 ModelBinders.Binders.Add(typeof(MvcStudy.Controllers.HomeController.TestA), new NSModelBinder());
然后我们重新编译,并在页面中输入值并提交,可以发现TestA的id并不是我们输入的值而是模型绑定器中的值,但是如果我们将Views/Home/Index.cshtml中的文本框的name改成ns.id之后,我们再输入值,最后显示的就是我们输入的值了,由此可以看出来模型绑定器是依赖于值提供器的。
至此关于模型绑定的部分就结束了,下面我们将开始学习模型验证。
.NET MVC学习之模型绑定的更多相关文章
- ASP.NET MVC学习之模型绑定(1)
一.前言 下面我们将开始学习模型绑定,通过下面的知识我们将能够理解ASP.NET MVC模型的模型绑定器是如何将http请求中的数据转换成模型的,其中我们重点讲述的是表单数据. 二.正文 1.简单类型 ...
- ASP.NET MVC学习之模型绑定(2)
3.手工调用模型绑定 很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了很多过程中的控制,所以我们就需要使用手工的方式进行绑定.下面我们通过一个例子来说明,首先打开 ...
- ASP.NET MVC学习之模型验证详解
ASP.NET MVC学习之模型验证篇 2014-05-28 11:36 by y-z-f, 6722 阅读, 13 评论, 收藏, 编辑 一.学习前的一句话 在这里要先感谢那些能够点开我随笔的博友们 ...
- Spring MVC系列之模型绑定(SpringBoot)(七)
前言 上一节我们在SpringBoot中启用了Spring MVC最终输出了HelloWorld,本节我们来讲讲Spring MVC中的模型绑定,这个名称来源于.NET或.NET Core,不知是否恰 ...
- [转]ASP.NET MVC 4 (九) 模型绑定
本文转自:http://www.cnblogs.com/duanshuiliu/p/3706701.html 模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C ...
- Asp.net Mvc 中的模型绑定
asp.net mvc中的模型绑定可以在提交http请求的时候,进行数据的映射. 1.没有模型绑定的时候 public ActionResult Example0() { ) { string id ...
- ASP.NET MVC 4 (九) 模型绑定
模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C#间起着桥梁的作用.模型绑定的一个最简单的例子是带参数的控制器action方法,比如我们注册这样的路径映射: ...
- 【ASP.NET Core】MVC 控制器的模型绑定(宏观篇)
欢迎来到老周的水文演播中心. 咱们都知道,MVC的控制器也可以用来实现 Web API 的(它们原本就是一个玩意儿),区别嘛也就是一个有 View 而另一个没有 View.于是,在依赖注入的服务容器中 ...
- ASP.NET MVC学习之模型验证篇
一.学习前的一句话 在这里要先感谢那些能够点开我随笔的博友们.慢慢的已经在博客园中度过一年半了,伊始只是将博客园作为自己学习的记录本一样使用,也不敢将自己的随笔发表到博客园首页,生怕自己的技艺不高,反 ...
随机推荐
- Linux IPC(Inter-Process Communication,进程间通信)之管道学习
1.标准流管道 管道操作支持文件流模式,用来创建链接还有一个进程的管道,通过函数popen和pclose popen的详细介绍在本blog:Linux 多进程学习中有具体介绍 2.无名管道(PIPE) ...
- react.js 从零开始(六)Reconciliation
Reconciliation React 的关键设计目标是使 API 看起来就像每一次有数据更新的时候,整个应用重新渲染了一样.这就极大地简化了应用的编写,但是同时使 React 易于驾驭,也是一 ...
- jsp 说明标签
page指令 Page指令用来定义整个JSP页面的一些属性和这些属性的值. 比如我们能够用page指令定义JSP页面的contentType属性的值是text/html;charset=GB2312, ...
- 对Unity3d C#手动处理异常产生
System.AppDomain.CurrentDomain.UnhandledException += new System.UnhandledExceptionEventHandler(_OnUn ...
- STL algorithmi算法s_sorted和is_sorted_until(28)
is_sort原型: ::is_sorted default (1) template <class ForwardIterator> bool is_sorted (ForwardIte ...
- WebAPI客户端
封装WebAPI客户端,附赠Nuget打包上传VS拓展工具 一.前言 上篇< WebAPI使用多个xml文件生成帮助文档 >有提到为什么会出现基于多个xml文件生成帮助文档的解决方案,因为 ...
- sscanf()函数的用法
来自:http://blog.csdn.net/tigerjibo/article/details/6442151 sscanf 名称: sscanf() - 从一个字符串中读进与指定格式相符的数据. ...
- DirectSound应用
只是使用的假设PlaySound()这个API函数来显示的声音效果,然后,然后,它不会出现在混合声音,因为PlaySound还有播放期间声音,这将不可避免地导致现有声音停止. 因此,使用 PlaySo ...
- 开源搜索引擎Iveely 0.8.0
开源搜索引擎Iveely 0.8.0 这是一篇博客,不是,这是一篇开源人的心酸和喜悦,没有人可以理解我们的心情,一路的辛酸一路的艰辛,不过还好,在大家的支持下,总算是终见天日,谢谢那些给予我们无私帮助 ...
- linux_ssky-keygen + ssh-copy-id 无密码登陆远程LINUX主机
使用下例中ssky-keygen和ssh-copy-id,仅需通过3个步骤的简单设置而无需输入密码就能登录远程Linux主机. ssh-keygen 创建公钥和密钥. ssh-copy-id 把本地主 ...