MVC 模型绑定

在WebForm,获取提交表单的值一般都是Request.Form["Title"]这样的方式。在MVC中,提供了模型绑定机制。让后台获取表单或Url中的参数变得更加简单。

一、基本模型绑定

  你可以直接在参数中用字符串,整型变量,实体或者是List<实体>的方式获取表单提交的参数。

  参数中的这些东西都是与表单中的Html控件的name属性一一对应的。

        public ActionResult PersonAdd(int Id)
        {
            return View();
        }

  例如以上代码,它能够匹配Url中的Id参数。如以下两种方法Id都能够匹配到1

  http://localhost/Home/PersonAdd/1
  http://localhost/Home/PersonAdd?Id=1

  在例如如下代码:

        public ActionResult PersonAdd(string Name)
        {
            return View();
        }

  它能够匹配到表单中提交的张三:

<input type="text" name="Name" value="张三" />

  也能够匹配到Get请求的路径参数:

http://localhost/Home/PersonAdd?Name=张三

  如果是用实体,则会检查该实体的属性名与表单中name属性中对应的标签的值。

  例如有如下实体:

    public class Person_Model
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }

  在Controller中的参数填写如下:

        [HttpPost]
        public ActionResult PersonAdd(Person_Model model)
        {
            if (ModelState.IsValid)  //此处仅作演示,不考虑安全性
            {
                //插入数据库省略
                return Redirect("/Home/PersonManager");
            }
            return View();
        }

  这样的话,模型绑定器会自动检查该实体的属性与Name一一对应的标签并绑定。如下表单的值将被绑定到model实体的属性中。

  <input type="hidden" name="Id" value="1" />
  <input type="text" name="Name" value="张三" />

二、显式模型绑定

  UpdateModel与TryUpdateModel都用于显示模型绑定。如果绑定期间出现错误或者模型是无效的。

  UpdateModel将抛出一个异常。因此UpdateModel要用try catch语句块包起来,而TryUpdateModel不会抛出异常,而是返回一个布尔类型的值,true表示绑定成功,false表示绑定失败。如:

        [HttpPost]
        public ActionResult PersonAdd()
        {
            Person_Model model = new Person_Model();
            try
            {
                UpdateModel(model);
                //插入数据库
                return Redirect("/Home/PersonManager");
            }
            catch
            {
                return View(model);
            }
        }

  TruUpdateModel:

        [HttpPost]
        public ActionResult PersonAdd()
        {
            Person_Model model = new Person_Model();
            if (TryUpdateModel(model))
            {
                //插入数据库
                return Redirect("/Home/PersonManager");
            }
            else
            {
                return View(model);
            }
        }

  另外,模型绑定还有一个模型状态,模型绑定器一斤模型中的每一个值在模型状态中都有相应的一条记录。可以随时查看绑定状态。如:

        [HttpPost]
        public ActionResult PersonAdd()
        {
            Person_Model model = new Person_Model();
            TryUpdateModel(model);
            if (ModelState.IsValid)
            {
                //if(ModelState.IsValidField("Name"))
                //插入数据库
                return Redirect("/Home/PersonManager");
            }
            else
            {
                return View(model);
            }
        }

三、安全问题:重复提交

  假设有如下实体:

    public class Comment
    {
        public int Id { get; set; }
        //评论者姓名
        public string Name { get; set; }
        //评论内容
        public string Content { get; set; }
        //是否已审核
        public bool Approved { get; set; }
    }

  在Controller中:

        public ActionResult CommentAdd(Comment com)
        {
            if (ModelState.IsValid)
            {
                //添加数据库
                return Redirect("/Home/CommentManager");
            }
            else
            {
                return View(com);
            }
        }

  在以上代码中,如果有恶意用户在表单数据中添加"Approved=true"来干预表单的提交,那么该评论将是默认就通过审核的。这时候我们可以使用Bind特性来防御重复提交攻击。

  白名单:

[Bind(Include="Name,Content")]      //白名单,只绑定这两个属性
[Bind(Exclude="Id,Approved")]        //黑名单,不绑定这两个属性

  Bind特性可以应用于参数左侧也可以应用于实体Model类的顶部,应用于实体Modle的顶部则是对所有该实体绑定有效,而应用于参数左侧则只是对该action中的请求有效。

  如:

public ActionResult CommentAdd([Bind(Exclude="Approved")]Comment com)
{
  if (ModelState.IsValid)
  {
    //添加数据库
    return Redirect("/Home/CommentManager");
  }
  else
  {
     return View(com);
  }
}

  另外,UpdateModel与TryUpdateModel也有一个重载版本来接收一个绑定列表:

UpdateModel(com, "", new string[] { "Id", "Name", "Content" });

  最后,还有一种就是视图模型,即另外在定义一个模型来专供视图使用,仅仅包括需要绑定的属性。

  另外,如果两个类有相同的Name属性,要同时绑定,区分HTML可以这样写:

<p>客户名称: <input type="text" name="customer.Name" style="width: 300px" /></p>
<p>销售员名称: <input type="text" name="salesman.Name" style="width: 300px" /></p>

三、模型绑定原理

  在ASP.NET MVC中,用户请求道服务器的数据将被包装为Model数据对象,这个数据对象通常也被View用来提供显示的数据。在ASP.NET MVC中,提供了非常灵活的Model绑定机制,通过IModelBinder借口,定义了绑定Model数据的约定,并提供了一个接口的默认实现DefaultModelBinder。在大多数情况下,仅仅通过DefaultModelBinder就可以完成Model的绑定。

  如果需要的话,也可以自定义一个IModelBinder的实现,完成特定类型的Model绑定。

public interface IModelBinder
{
    object BindModel(ControllerContext controllerContext,ModelBindContext bindingContext);
}

  1、绑定Model

  默认情况下,ASP.NET MVC使用DefaultModelBinder来绑定Model的数据。在传递Action参数的时候,ASP.NET MVC按照如下顺序查找匹配的数据:

  1. form表单中的数据;
  2. RouteData中的数据;
  3. QueryString中的数据;

  2、简单参数和复杂参数

  如果Action方法的参数类型是值类型和字符串类型,那么DefaultModelBinder将寻找与Action参数名称匹配的参数,如果没有对应的参数,那么Action的参数将试图赋予空引用。因此,对于简单类型的参数来说,参数的类型应该是可空的。

  多数情况下,我们会通过一个Model对象来处理复杂的参数,DefaultModelBinder会遍历Model对象的属性来绑定参数。   如果不希望DefaultModelBinder对某个参数进行绑定,可以通过BindAttribute进行说明,其中定义了三个属性:

  • Include表示需要绑定的属性,各个属性之间以逗号进行分隔。
  • Exclude表示不需要绑定的属性,各个属性之前以逗号分隔。
  • Prefix表示请求参数的前缀。

  这些标签可以定义在Model上,说明在参数绑定过程中需要绑定的属性或者不需要绑定的属性,如:

[Bind(Include = "Name,Birthday")]
public class Person
{
  public int Id { get; set; }
  public string Name { get; set; }
  public DateTime Birthday{ get; set; }
}

  在UpdateModel方法中,指定包含的属性和不包含的属性。

UpdateModel(
  person,     //Model
  "person",    //Prefix
  new[] { "Id","Name" },  //Include
  new [] { "Birthday" }   //Exclude
);
时间: 2024-11-11 20:43:18

MVC 模型绑定的相关文章

[转] ASP.NET MVC 模型绑定的功能和问题

摘要:本文将与你深入探究 ASP.NET MVC 模型绑定子系统的核心部分,展示模型绑定框架的每一层并提供扩展模型绑定逻辑以满足应用程序需求的各种方法. 同时,你还会看到一些经常被忽视的模型绑定技术,并了解如何避免一些最常见的模型绑定错误. ASP.NET MVC 模型绑定通过引入自动填充控制器操作参数的抽象层.处理通常与使用 ASP.NET 请求数据有关的普通属性映射和类型转换代码来简化控制器操作. 虽然模型绑定看起来很简单,但实际上是一个相对较复杂的框架,由许多共同创建和填充控制器操作所需对

MVC模型绑定

视图: 1 @model RegisterViewModel 2 @{ 3 ViewData["Title"] = "Register"; 4 } 5 6 <h2>@ViewData["Title"]</h2> 7 8 <div class="row"> 9 <div class="col-md-4"> 10 <form asp-route-return

ASP.NET MVC——模型绑定

这篇文章我们来讲讲模型绑定(Model Binding),其实在初步了解ASP.NET MVC之后,大家可能都会产生一个疑问,为什么URL片段最后会转换为例如int型或者其他类型的参数呢?这里就不得不说模型绑定了.模型绑定是指,用浏览器以HTTP请求方式发送的数据来创建.NET对象的过程.每当定义具有参数的动作方法时,一直是在依赖着这种模型绑定过程. 准备项目 我们先来创建一个MVC项目,名叫MVCModels,并在Models文件夹中创建一个新的类文件Person. 1 using Syste

ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)

前面文章介绍了ASP.NET MVC中的模型绑定和验证功能,本着ASP.NET MVC没有魔法的精神,本章内容将从代码的角度对ASP.NET MVC如何完成模型的绑定和验证进行分析,已了解其原理. 本文的主要内容有: ● ModelBinder ● ValuePrivoder ● ModelMetadata ● 简单模型与复杂模型 ● 小结 ModelBinder ModelBinder是ASP. NET MVC用于模型绑定的核心组件,所有的ModelBinder都实现了IModelBinder

asp.net mvc 模型绑定太糙淡了

之前就偶尔遇到模型绑定失效的问题,一直怪自己技术渣渣 不懂人家 而已.最近又遇到 自定义类 绑定失败,看了大牛scot文档 也不得姐..&……**……&*……*…………*%%(此处一堆脏话) 干脆自己直接丰庄个扩展方法,解析request 反序列.效果倍儿好!再也不担心模型绑定失效了,参数我想怎么传就怎么穿,顺带避免了微软时间/date*****/ 的大坑 哇哈哈哈.---------------------既然别人提供的封装方法那么难使 为嘛不自己造个? 大不了一样糙蛋呗 oh yeah

ASP.NET Core MVC/WebAPi 模型绑定探索

前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用到了,你再去看理论性的文章时才会豁然开朗,这是我一直以来学习技术的方法.本文我们来讲解.NET Core中的模型绑定. 话题 在ASP.NET Core之前MVC和Web APi被分开,也就说其请求管道是独立的,而在ASP.NET Core中,WebAPi和MVC的请求管道被合并在一起,当我们建立控

ASP.NET MVC 的自定义模型绑定

最近在研究 ASP.NET MVC 模型绑定,发现 DefaultModelBinder 有一个弊端,就是无法实现对浏览器请求参数的自定义,最初的想法是想为实体模型的属性设置特性(Attribute),然后通过取得设置的特性值对属性进行赋值,研究了好久 MVC 源码之后发现可以通过重写 DefaultModelBinder 的 BindProperty 方法可以达到预期的目的. ASP.NET MVC 中有一个自定义模型绑定特性 CustomModelBinderAttribute,打算通过重写

【转】ASP.NET Core MVC/WebAPi 模型绑定探索

前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用到了,你再去看理论性的文章时才会豁然开朗,这是我一直以来学习技术的方法.本文我们来讲解.NET Core中的模型绑定. 话题 在ASP.NET Core之前MVC和Web APi被分开,也就说其请求管道是独立的,而在ASP.NET Core中,WebAPi和MVC的请求管道被合并在一起,当我们建立控

net core 模型绑定与之前版本的不同

之前有一个用于七牛上传图片的Callback Url的WebAPI (之前是用.net4.0,运行正常) 代码如下: // 七牛CallBack地址,CallbackBody内容name=upload/member/1.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2 public object Post([FromBody]dynamic data) { ILog logger = LogManager.GetLogger(System.Reflection.Meth