ASP.NET MVC 5 Model Binding

Default Model Binder

The Order in Which the DefaultModelBinder Class Looks for Parameter Data:

  1. Request.Form - Values provided by the user in HTML form elements
  2. RouteData.Values - The values obtained using the application routes
  3. Request.QueryString - Data included in the query string portion of the request URL
  4. Request.Files - Files that have been uploaded as part of the request

Bind to simple type:

The DefaultModelBinder tries to convert the string value, which has been obtained from the request data into the parameter type using the System.ComponentModel.TypeDescriptor class. If the value cannot be converted, then the DefaultModelBinder won’t be able to bind to the model.

Bind to complex type:

Then the DefaultModelBinder class uses reflection to obtain the set of public properties and then binds to each of them in turn. If a property requires another complex type, then the process is repeated for the new type. The set of public properties are obtained and the binder tries to find values for all of them. The difference is that the property names are nested.

Specifying Custom Prefixes:

There are occasions when the HTML you generate relates to one type of object, but you want to bind it to another. In this case, you can use Bind attribute to the action method parameter, which tells the binder which prefix to look for. Below example binds HomeAddress to AddressSummary.

public ActionResult DisplaySummary([Bind(Prefix="HomeAddress")]AddressSummary summary) {
  return View(summary);
}

Selectively Binding Properties:

The Exclude property of the Bind attribute allows you to exclude properties from the model binding process. Below example won‘t bind Country property.

public ActionResult DisplaySummary([Bind(Prefix="HomeAddress", Exclude="Country")]AddressSummary summary) {
    return View(summary);
}

As an alternative, you can use the Include property to specify only those properties that should be bound in the model; all other properties will be ignored.

When the Bind attribute is applied to an action method parameter, it only affects instances of that class that are bound for that action method; all other action methods will continue to try and bind all the properties defined by the parameter type. If you want to create a more widespread effect, then you can apply the Bind attribute to the model class itself.

namespace MvcModels.Models {
  [Bind(Include="City")]
  public class AddressSummary {
    public string City { get; set; }
    public string Country { get; set; }
  }
}

Binding to Arrays:

The default model binder sees that the action method requires an array and looks for data items that have the same name as the parameter.

Action Method:

public ActionResult Names(string[] names) {
  names = names ?? new string[0];
  return View(names);
}

Generated Html Code:

<form action="/Home/Names" method="post">
  <div>
    <label>1:</label>
    <input id="names" name="names" type="text" value="" />
  </div>
  <div>
    <label>2:</label>
    <input id="names" name="names" type="text" value="" />
  </div>
  <div>
    <label>3:</label>
    <input id="names" name="names" type="text" value="" />
  </div>
  <button type="submit">Submit</button>
</form>

Binding to Collections:

The default model binder sees that the action method requires a collection and looks for data items that have the same name as the parameter.

Action Method:

public ActionResult Names(IList<string> names) {
  names = names ?? new List<string>();
  return View(names);
}

Generated Html Code:

<form action="/Home/Names" method="post">
  <div>
    <label>1:</label>
    <input id="names" name="names" type="text" value="" />
  </div>
  <div>
    <label>2:</label>
    <input id="names" name="names" type="text" value="" />
  </div>
  <div>
    <label>3:</label>
    <input id="names" name="names" type="text" value="" />
  </div>
  <button type="submit">Submit</button>
</form>

Binding to Collections of Custom Model Types:

Action Method:

public ActionResult Address(IList<AddressSummary> addresses) {
  addresses = addresses ?? new List<AddressSummary>();
  return View(addresses);
}

Generated Html Code:

<fieldset>
  <legend>Address 1</legend>
  <div>
    <label>City:</label>
    <input class="text-box single-line" name="[0].City" type="text" value="" />
  </div>
  <div>
    <label>Country:</label>
    <input class="text-box single-line" name="[0].Country" type="text" value="" />
  </div>
</fieldset>
<fieldset>
  <legend>Address 2</legend>
  <div>
    <label>City:</label>
    <input class="text-box single-line" name="[1].City" type="text" value="" />
  </div>
  <div>
    <label>Country:</label>
    <input class="text-box single-line" name="[1].Country" type="text" value="" />
  </div>
</fieldset>

When the Html form is submitted, the default model binder realizes that it needs to create a collection of AddressSummary objects and uses the array index prefixes in the name attributes to obtain values for the object properties. The properties prefixed with [0] are used for the first AddressSummary object, those prefixed with [1] are used for the second object, and so on.

Manually Invoking Model Binding

public ActionResult Address() {
    IList<AddressSummary> addresses = new List<AddressSummary>();
    UpdateModel(addresses);
    return View(addresses);
}

The UpdateModel method takes a model object that I was previously defining as a parameter and tries to obtain values for its public properties using the standard binding process.

public ActionResult Address() {
    IList<AddressSummary> addresses = new List<AddressSummary>();
    UpdateModel(addresses, new FormValueProvider(ControllerContext));
    return View(addresses);
}

When I manually invoke the binding process, I am able to restrict the binding process to a single source of data. By default, the binder looks in four places: form data, route data, the query string, and any uploaded files.

The Built-in IValueProvider Implementations:

  1. Request.Form - FormValueProvider
  2. RouteData.Values - RouteDataValueProvider
  3. Request.QueryString - QueryStringValueProvider
  4. Request.Files - HttpFileCollectionValueProvider
public ActionResult Address(FormCollection formData) {
  IList<AddressSummary> addresses = new List<AddressSummary>();
  UpdateModel(addresses, formData);
  return View(addresses);
}

The FormCollection class implements the IValueProvider interface, and if I define the action method to take a parameter of this type, the model binder will provide me with an object that I can pass directly to the UpdateModel method.

Dealing with Binding Errors

public ActionResult Address(FormCollection formData) {
    IList<AddressSummary> addresses = new List<AddressSummary>();
    if (TryUpdateModel(addresses, formData)) {
    // proceed as normal
    } else {
    // provide feedback to user
    }
    return View(addresses);
}

Customizing the Model Binding System

Creating a Custom Value Provider

Creating a Custom Model Binder

Registering the Custom Model Binder

Registering a Model Binder with an Attribute

时间: 2024-11-09 05:19:11

ASP.NET MVC 5 Model Binding的相关文章

ASP.NET MVC中Model相关技术

在Model里的程序,由于“只能”跟数据与商业逻辑有关,因此Model专注于如何有效地提供数据访问机制.交易环境.数据格式.商业逻辑验证等工作. 一.使用Code First创建数据模型 数据库开发模式有数据库优先开发模式(Database First Development).模型优先开发模式(Model First Development)和程序代码优先开发模式(Code First Development)这三种.ASP.NET MVC的Model数据库开发模式为程序代码优先开发模式,使用

ASP.NET MVC传递Model到视图的多种方式总结

ASP.NET MVC传递Model到视图的多种方式总结 有多种方式可以将数据传递到视图,如下所示: ViewData ViewBag PartialView TempData ViewModel Tuple 场景: 在视图页面,下拉框选择课程触发事件,分别显示老师课程表.学生上课表,如图: 相关的Model: 1 public class Course 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5

ASP.NET MVC传递Model到视图的多种方式之通用方式的使用

ASP.NET MVC传递Model到视图的多种方式总结——通用方式的使用 有多种方式可以将数据传递到视图,如下所示: ViewData ViewBag PartialView TempData ViewModel Tuple 场景: 在视图页面,下拉框选择课程触发事件,分别显示老师课程表.学生上课表,如图: ? 相关的Model: 1 public class Course 2 { 3 public int Id { get; set; } 4 public string Name { get

ASP.NET MVC中Model元数据解析学习

闲来继续学习蒋金楠大师的ASP.NET MVC框架揭秘一书,当前主要阅读的内容是Model元数据的解析,即使是阅读完的现在,仍然有不少细节不是特别明白.好在这部分内容主要是关于Razor引擎的呈现的,通过注解的方式对Model进行自定的修饰,最终使得页面在渲染时(即从cshtml文件转化为html时),相关的数据能够按照指定的形式转化并显示.由于接下来的项目中不再打算使用Razor引擎,该引擎虽然很不错,但也有一些问题,例如存在HTML5代码与HtmlHelper的混写,使得UI层很难与业务代码

仅此一文让你明白ASP.NET MVC 之Model的呈现

本文目的 我们来看一个小例子,在一个ASP.NET MVC项目中创建一个控制器Home,只有一个Index: public class HomeController : Controller { public ActionResult Index() { var model = new DemoModel {Email = "[email protected]"}; return View(model); } } public class DemoModel { [DataType(D

MVC中model binding的坑

这两天发现一个model binding中的坑,就是action中的参数名不能和属性重复,否则绑定不了,参数始终是null, 举例说明: T_Account类定义如下 public partial class T_Account { [Key] public int Id { get; set; } [Required] [StringLength(50)] public string Account { get; set; } [StringLength(50)] public string

ASP.NET MVC 5 Model Validation

Explicitly Validating a Model [HttpPost] public ViewResult MakeBooking(Appointment appt) { if (string.IsNullOrEmpty(appt.ClientName)) { ModelState.AddModelError("ClientName", "Please enter your name"); } if (ModelState.IsValidField(&qu

asp.net mvc 提交model 接收不了

[HttpPost]        //[ValidateInput(false)]        public ActionResult AddNews1(_54Young_News_Model.model.gou54contentall contentmodel, _54Young_News_Model.model.gou54user usermodel)        {} 发现用一些特殊符号提交不了, 然后以为说前端问题,把model去掉就可以了. 后面觉得是因为有特殊符号影响到转mod

ASP.NET MVC - loop model data in javascript

Key: razor syntax using @: before the js variable in c# code block Example: var chartData = []; @for(int i=0; i < Model.ModuleDetails.Count; i++) { @: chartData.push(@Html.Raw(Json.Encode(Model.ModuleDetails[i].ChartData.ToArray()))); } reference: ht