看到很多ASP.NET MVC项目还在从request.querystring或者formContext里面获取数据,这实在是非常落后的做法。也有的项目建了大量的自定义的modelbinder,以为很牛,实际上也落后的很。

ASP.NET MVC提供了IModelBinder的默认实现,这个实现的类就叫DefaultModelBinder。我们在写代码的时候,几乎感觉不到这个类的存在,因为这个类自动将request信息解析成action参数。本文将向大家展示这个类是多么强大,可以拯救大量的代码。

先看个例子。假如有如下表单,用于编辑用户信息以及该用户的时间表。在这个例子中,我要利用DefaultModelBinder自动将整个表单数据解析成复杂实体类的实例。一行手工解析的C#代码都不用写。

对应的controller的代码如下,很简单:

 public class DemoController : PublicControllerBase
{
public ActionResult UserEditor()
{
return View();
} [HttpPost]
public string SaveUser(DemoUser user)
{
var result = string.Empty;
if (user != null)
{
result = Serializer.ToJson(user);
}
return result;
}
}

相关的实体类的定义,也很简单:

public class DemoUser
{
public string Username { get; set; }
public string Email { get; set; }
public string Language { get; set; }
public Gender Gender { get; set; }
public int[] RoleIds { get; set; }
public List<ScheduledJob> Jobs { get; set; }
} public class ScheduledJob
{
public string Job { get; set; }
public string From { get; set; }
public string To { get; set; }
} public enum Gender
{
Unknown = ,
Male = ,
Female =
}

请注意SaveUser这个action的参数,一个比较复杂的实体类的对象。DefaultModelBinder会自动将这个复杂的表单解析出来。这个保存的action将参数user直接序列化JSON字符串返回到浏览器。

下面看看HTML和JS。

HTML:

 <form id="formUserEditor" action="/demo/saveuser" method="POST">
<table class="form">
<colgroup>
<col width="100"/>
<col width="auto"/>
</colgroup>
<tbody>
<tr>
<td>用户名:</td>
<td>
<input id="txtUsername" type="text" name="username" />
</td>
</tr>
<tr>
<td>Email:</td>
<td>
<input id="txtEmail" type="text" name="email" />
</td>
</tr>
<tr>
<td>语言:</td>
<td>
<select id="ddlLanguages" name="language">
<option value="zh-cn">中文</option>
<option value="en-us">英文</option>
</select>
</td>
</tr>
<tr>
<td>性别:</td>
<td id="genders">
<input type="radio" name="gender" value="@(Taoad.Web.Publics.Controllers.Gender.Unknown)" id="rdUnknown" />
<label for="rdUnknown">未知</label> <input type="radio" name="gender" value="@(Taoad.Web.Publics.Controllers.Gender.Male)" id="rdMale" />
<label for="rdMale">男</label> <input type="radio" name="gender" value="@(Taoad.Web.Publics.Controllers.Gender.Female)" id="rdFemale" />
<label for="rdFemale">女</label>
</td>
</tr>
<tr>
<td>角色:</td>
<td id="roles">
<input type="checkbox" name="roleids" value="1" id="cb1" />
<label for="cb1">管理员</label> <input type="checkbox" name="roleids" value="2" id="cb2" />
<label for="cb2">部门经理</label> <input type="checkbox" name="roleids" value="3" id="cb3" />
<label for="cb3">客户</label>
</td>
</tr>
<tr>
<td>时间:</td>
<td>
<ul id="jobs"> </ul>
<input type="button" value="添加" id="btnAddJob"/>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="button" value="保存" id="btnSave"/>
<input type="button" value="取消" id="btnCancel" />
</td>
</tr>
</tbody>
</table>
</form>
<hr/>
<div id="json"> </div>

JS:

 <script language="javascript" type="text/javascript">
$(document).ready(function () {
$("#btnAddJob").click(function() {
var $newLi = $(html);
$("#jobs").append($newLi);
bindLi($newLi);
}); $("#btnSave").click(function() {
var data = $("#formUserEditor").serialize();
$("#jobs li").each(function(i) {
var prefix = "&jobs[" + i + "]";
data += prefix + ".job=" + $(this).find(".job-id").val();
data += prefix + ".from=" + $(this).find(".job-from").val();
data += prefix + ".to=" + $(this).find(".job-to").val();
});
demo.ajax.post("/demo/saveuser", data, function(json) {
$("#json").html(json);
});
});
}); function bindLi(li) {
$(li).find(".btn-add").click(function () {
var $li = $(this).closest("li");
var $newLi = $(html);
$li.after($newLi);
bindLi($newLi);
});
$(li).find(".btn-delete").click(function () {
$(this).closest("li").remove();
});
} var html = '<li>\
<select class="job-id">\
<option value="job1">工作1</option>\
<option value="job2">工作2</option>\
</select>\
<input type="text" placeholder="开始时间" class="job-from"/>\
————\
<input type="text" placeholder="结束时间" class="job-to"/>\
<a href="javascript:void(0);" class="btn-add">添加</a> |\
<a href="javascript:void(0);" class="btn-delete">删除</a>\
</li>';
</script>

如果是如下的表单数据:

点击保存之后,返回的JSON数据为:

可以看到所有的表单数据都保存成功了。

再看看request信息:

请注意content-type的值。

实际上,POST到服务器的表单数据只是一个字符串,如下:

复制出来就是下面这样的字符串:

ajax=true&username=leo&email=leo%40gmail.com&language=zh-cn&gender=Unknown&roleids=1&roleids=3&jobs[0].job=job1&jobs[0].from=9:00&jobs[0].to=10:00&jobs[1].job=job2&jobs[1].from=10:00&jobs[1].to=11:00

由此可知,可用JS来拼接字符串,将整个表单通过键值对的形式序列化成一个字符串,再将该字符串传到服务器,这时DefaultModelBinder就可以自动解析实体类了。

关键点在于,对于List或者数组类型的数据,要加上数组下标。这样,任意复杂的数据结构,DefaultModelBinder都可以自动解析了。

思考一:

如果表单数据的键带有”demouser”的前缀,如下所示,那么这个action的参数还能自动解析吗?

Demouser.username=leo&demouser.email=leo@gmail.com&demouser.jobs[0].job=job1&.....

Action如下:

 [HttpPost]
public string SaveUser(DemoUser user)
{
var result = string.Empty;
if (user != null)
{
result = Serializer.ToJson(user);
}
return result;
}

如果action参数名称又改成demouser呢?

思考二:

如果将action的参数名称改成如下代码所示,那么是否可以自动解析?(表单数据不带”demouser”前缀)

ajax=true&username=leo&email=leo%40gmail.com&language=zh-cn&gender=Unknown&roleids=1&roleids=3&jobs[0].job=job1&jobs[0].from=9:00&jobs[0].to=10:00&jobs[1].job=job2&jobs[1].from=10:00&jobs[1].to=11:00

Action如下:

 [HttpPost]
public string SaveUser(DemoUser demoUser)
{
var result = string.Empty;
if (demoUser != null)
{
result = Serializer.ToJson(demoUser);
}
return result;
}

思考三:

如果action的参数是用另一个类包起来了,如下代码所示,那么表单数据应该是怎么样的字符串才能使DefaultModelBinder可以自动解析?

 public class UserEditorViewModel
{
public DemoUser DemoUser { get; set; }
} [HttpPost]
public string SaveUser(UserEditorViewModel model)
{
var result = string.Empty;
if (model != null)
{
result = Serializer.ToJson(model);
}
return result;
}

思考四:

如果action是这样定义的,那么表单数据的字符串又该怎么拼?

 [HttpPost]
public string SaveUser(DemoUser demoUser, List<ScheduledJob> scheduledJobs)
{
var result = string.Empty;
if (demoUser != null)
{
demoUser.Jobs = scheduledJobs;
result = Serializer.ToJson(demoUser);
}
return result;
}

欢迎讨论。

你从未知道如此强大的ASP.NET MVC DefaultModelBinder的更多相关文章

  1. ASP.NET MVC DefaultModelBinder

    转载自 Leo‘s Blog 看到很多ASP.NET MVC项目还在从request.querystring或者formContext里面获取数据,这实在是非常落后的做法.也有的项目建了大量的自定义的 ...

  2. ASP.NET MVC分页组件MvcPager 2.0版发布暨网站全新改版

    MvcPager分页控件是在ASP.NET MVC Web应用程序中实现分页功能的一系列扩展方法,该分页控件的最初的实现方法借鉴了网上流行的部分源代码, 尤其是ScottGu的PagedList< ...

  3. MvcPager 概述 MvcPager 分页示例 — 标准Ajax分页 对SEO进行优化的ajax分页 (支持asp.net mvc)

    该示例演示如何使用MvcPager最基本的Ajax分页模式. 使用AjaxHelper的Pager扩展方法来实现Ajax分页,使用Ajax分页模式时,必须至少指定MvcAjaxOptions的Upda ...

  4. ASP.NET MVC学习之视图篇(1)

    一.前言 不知道还有多少读者从第一篇开始一直学习到如今,笔者也会一直坚持将ASP.NET MVC的学习完美的结束掉,然后开始写如何配合其他框架使用ASP.NET MVC的随笔.当然笔者后面的随笔如果没 ...

  5. 应用程序框架实战三十三:表现层及ASP.NET MVC介绍(二)

    最近的更新速度越来越慢,主要是项目上比较忙,封装EasyUi也要花很多时间.不过大家请放心,本系列不会半途夭折,并且代码干货也会持续更新.本文继续介绍表现层和Asp.net Mvc,我将在本篇讨论一些 ...

  6. ASP.NET MVC 应用提速的十种方法

    [编者按]本文作者为 DZone 社区的最具价值博主(MVB) Jonathan Danylko,主要介绍为 ASP.NET MVC 应用提速的十种方法.由国内 ITOM 管理平台 OneAPM 编译 ...

  7. asp.net mvc vs web form

    译者介绍 小小.NET学童,滴答…滴答…的雨…… 正文如下======================================================= 原文示例(VS2012): 1 ...

  8. 表现层及ASP.NET MVC介绍(二)

    表现层及ASP.NET MVC介绍(二) 最近的更新速度越来越慢,主要是项目上比较忙,封装EasyUi也要花很多时间.不过大家请放心,本系列不会半途夭折,并且代码干货也会持续更新.本文继续介绍表现层和 ...

  9. 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结

    为什么说JAVA中要慎重使用继承   这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...

随机推荐

  1. NiceMark——我的Markdown编辑器

    NiceMark--我的Markdown编辑器 闲来无事,写了一个Markdown编辑器.基于electron,完全采用Web前段技术(Html,css,JavaScript)实现.代码已托管在Git ...

  2. session实现购物车

    为实现简单的购物功能(购物车添加.账户查看.购物车商品删除.实时的购物商品数量及价格的计算显示.购物车商品数量可手动输入等),用session实现了一简单的以php语言为基础.连接MySQL数据库的购 ...

  3. Javascript实用方法

    这篇我主要记录一些在工作中常用的.实用的方法. String trim 字符串方法中的trim主要用来去空格使用,很多时候,在后台做参数处理的时候,我们都会使用该方法,比如在获取用户输入的账户时 va ...

  4. Intel Media SDK H264 encoder GOP setting

    1 I帧,P帧,B帧,IDR帧,NAL单元 I frame:帧内编码帧,又称intra picture,I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随 ...

  5. 使用SwingBench 对Oracle RAC DB性能 压力测试

    我们可以使用swingbench这个工具对数据库性能进行压力测试,得到一些性能指标作为参考. SwingBench下载: http://www.dominicgiles.com/downloads.h ...

  6. ASP.NET MVC——模型绑定

    这篇文章我们来讲讲模型绑定(Model Binding),其实在初步了解ASP.NET MVC之后,大家可能都会产生一个疑问,为什么URL片段最后会转换为例如int型或者其他类型的参数呢?这里就不得不 ...

  7. java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)

    一.Condition 类 在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的 java.util.c ...

  8. 推荐10款超级有趣的HTML5小游戏

    HTML5的发展速度比任何人的都想像都要更快.更加强大有效的和专业的解决方案已经被开发......甚至在游戏世界中!这里跟大家分享有10款超级趣味的HTML5游戏,希望大家能够喜欢! Kern Typ ...

  9. Supermap iCloudManager -负载均衡

    Supermap icm负载均衡理解: 应用场景:地图出图 子节点1和子节点2中的服务保持一致,一般情况下设置的是匿名用户通过nginx访问服务信息,所以不需要登录. 1.通过nginx分发请求,(轮 ...

  10. mysql百万级分页优化

    普通分页 数据分页在网页中十分多见,分页一般都是limit start,offset,然后根据页码page计算start , 这种分页在几十万的时候分页效率就会比较低了,MySQL需要从头开始一直往后 ...