[转]Asp.Net MVC使用HtmlHelper渲染,并传递FormCollection参数的陷阱
2016-01-17 22:24
746 查看
http://www.cnblogs.com/errorif/archive/2012/02/13/2349902.html
在Asp.Net MVC
1.0编程中,我们经常遇见这样的场景,在新建一个对象时候,通过HtmlHelper的方式在View模型中渲染Html控件,当填写完相关内容后,通过Form把需要新建的内容Post回View对应Controller的Action(例如:Create),指定的Action可以通过接受FormCollection参数、值参数或者某个类的实例参数(比如:Movie类),完成新建的操作。(主要指HtmlHelper.TextBox)
当我们通过传递FormCollection参数进行操作时,如果不使用UpdateModel方法,而利用ModelState.IsValid及ModelState.AddModelError实现错误校验提示等操作。这个时候,小心陷阱。
【注:本文章源代码通过VS2008创建】
1、View模型中HtmlHelper绑定数据的顺序
开始前,让我们先了解下View模型中HtmlHelper绑定数据的顺序(主要指HtmlHelper.TextBox,其它还未研究)
我们知道,当View使用了HtmlHelper进行控件渲染的时候,HtmlHelper会通过键值尝试填充我们曾经填写过的数据,以防止用户从头填写。(比如:我们填写表单,提交,当出现验证错误的时候,我们希望表单刷新后曾经填写的内容依然存在,而不是全部要重新填写。而HtmlHelper就是这样帮助我们的)。HtmlHelper填充数据的顺序如下:
(1)通过键值调用ModelState集合对应的System.Web.Mvc.ModelState实例的Value属性获取
(2)通过HtmlHelper指定的值填充(Html.TextBox("Title",指定值))
(3)通过键值获取ViewData内的对应数据
(4)通过键值获取View中强类型的Model对象对应属性的数据
(5)不填充
2、 传递FormCollection参数,不使用UpdateModel引起的异常
先看一个简单的例子(源代码下载)。View通过Post传递FormCollection参数到对应Controller的Create
Action,Create
Action检验参数是否合法。如果合法,暂时什么都不做;如果不合法,则通过ModelState的AddModelError添加错误信息,并通过ModelState.
IsValid判断,如果无效,重新返回该View。
(1) View代码(没有任何特殊的地方,HtmlHelper使用Html.TextBox("Title")的方式):
<asp:Content
ID="Content1"
ContentPlaceHolderID="TitleContent"
runat="server">
Create
</asp:Content>
<asp:Content
ID="Content2"
ContentPlaceHolderID="MainContent"
runat="server">
<h2>Create</h2>
<%=
Html.ValidationSummary("Create was unsuccessful.
Please correct the errors and try again.") %>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Title">Title:</label>
<%= Html.TextBox("Title") %>
<%=
Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="Director">Director:</label>
<%= Html.TextBox("Director") %>
<%=
Html.ValidationMessage("Director", "*") %>
</p>
<p>
<label for="Remark">Remark:</label>
<%= Html.TextBox("Remark") %>
<%=
Html.ValidationMessage("Remark", "*") %>
</p>
<p>
<input type="submit"
value="Create" />
</p>
</fieldset>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
复制代码
(2) Controller中Create Action代码
对应的Create
Action代码如下,我们通过UpdateModel来进行Movie类的填充,而是直接创建了一个Movie类的实例(我直接在Controller的Action中验证参数,虽然我知道这样做不对,这里只是个例子。):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
复制代码
(3) 运行结果
大家可以下载代码运行,结果如下:当不输入参数,提交表单时,我们希望这个时候能够提示“Title 不能为空!”和“Director
不能为空!”。但是,很不幸,报错了。
public ActionResult Create(FormCollection collection)
复制代码
大家可以下载代码,运行:当不输入参数时,提示“Title 不能为空!”和“Director
不能为空!”,一切正常。
[align=center]
public ActionResult
Create(string Title,string
Director,string Remark){}[/align]
[align=left] [/align]
[align=left]复制代码[/align]
那不会出现问题。因为当传递的是类或者参数时,默认的ModelBinder除了会实例化Movie类并匹配属性或给参数赋值外,还会根据键值填充ModelState集合,就像UpdateModel会帮你做这件事情一样。
6、 小结
(1) Controller中的ModelState集合是个很重要的东西,它是System.Web.Mvc.ModelState类的集合,System.Web.Mvc.ModelState的实例会负责保存键值匹配的输入值(Value属性)、以及验证错误信息(Errors属性)。
(2) Post方式传递类参数、值参数时,会通过默认的ModelBinder来填充ModelState集合。
(3) UpdateModel方法也会填充ModelState集合。
(4) 如果使用HtmlHelper,并传递FormCollection参数,又需要通过ModelState.AddModelError添加错误验证信息,则需要调用UpdateModel方法或通过ModelState.Add方法来填充ModelState集合。
(5) 使用HtmlHelper渲染View中的控件数据的时候(主要指HtmlHelper.TextBox,其它还未研究),绑定顺序为:ModelState集合、指定值、ViewData内的数据、View中强类型Model对象对应属性的数据。
7、PS:
如果通过Asp.Net MVC 1.0做数据验证的时候,我们通常不会直接在Controller中的Action里面做,提供几个开源的工具和几篇文章:
n FluentValidation
下载地址:http://www.codeplex.com/FluentValidation
文章:/article/4753293.html
n Data Annotation Model Binder
下载地址:http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471
文章:http://www.asp.net/learn/mvc/tutorial-39-cs.aspx
或者Google 4 : Asp.Net MVC 数据验证
8、补充:
根据回复补充:
一、View模型中采用了HtmlHelper("Title",Model.Title)的方式
如果View模型中采用了HtmlHelper("Title",Model.Title)的方式,在第一次进入Create Action的时候,需要给ViewData.Model赋值,如果是Post回的Create Action,如果还需要显示这个View,也需要给ViewData.Model赋值,否则View模型中的Model为NULL,也会提示未将对象应用设置到对象值的实例”。给ViewData.Model赋值有两种方法(二选一):
1、在Create Action中给ViewData.Model赋值
ViewData.Model = new Movie() (第一次进入Create Action调用)
ViewData.Model = m(Post回Create Action时候调用,m为手动、自动或者传递参数过来的Movie对象实例)
2、返回使用带TModel参数的重载函数View(TModel)
Return View(new Movie())(说明同上)
Return View(m)(说明同上)
在Asp.Net MVC
1.0编程中,我们经常遇见这样的场景,在新建一个对象时候,通过HtmlHelper的方式在View模型中渲染Html控件,当填写完相关内容后,通过Form把需要新建的内容Post回View对应Controller的Action(例如:Create),指定的Action可以通过接受FormCollection参数、值参数或者某个类的实例参数(比如:Movie类),完成新建的操作。(主要指HtmlHelper.TextBox)
当我们通过传递FormCollection参数进行操作时,如果不使用UpdateModel方法,而利用ModelState.IsValid及ModelState.AddModelError实现错误校验提示等操作。这个时候,小心陷阱。
【注:本文章源代码通过VS2008创建】
1、View模型中HtmlHelper绑定数据的顺序
开始前,让我们先了解下View模型中HtmlHelper绑定数据的顺序(主要指HtmlHelper.TextBox,其它还未研究)
我们知道,当View使用了HtmlHelper进行控件渲染的时候,HtmlHelper会通过键值尝试填充我们曾经填写过的数据,以防止用户从头填写。(比如:我们填写表单,提交,当出现验证错误的时候,我们希望表单刷新后曾经填写的内容依然存在,而不是全部要重新填写。而HtmlHelper就是这样帮助我们的)。HtmlHelper填充数据的顺序如下:
(1)通过键值调用ModelState集合对应的System.Web.Mvc.ModelState实例的Value属性获取
(2)通过HtmlHelper指定的值填充(Html.TextBox("Title",指定值))
(3)通过键值获取ViewData内的对应数据
(4)通过键值获取View中强类型的Model对象对应属性的数据
(5)不填充
2、 传递FormCollection参数,不使用UpdateModel引起的异常
先看一个简单的例子(源代码下载)。View通过Post传递FormCollection参数到对应Controller的Create
Action,Create
Action检验参数是否合法。如果合法,暂时什么都不做;如果不合法,则通过ModelState的AddModelError添加错误信息,并通过ModelState.
IsValid判断,如果无效,重新返回该View。
(1) View代码(没有任何特殊的地方,HtmlHelper使用Html.TextBox("Title")的方式):
<asp:Content
ID="Content1"
ContentPlaceHolderID="TitleContent"
runat="server">
Create
</asp:Content>
<asp:Content
ID="Content2"
ContentPlaceHolderID="MainContent"
runat="server">
<h2>Create</h2>
<%=
Html.ValidationSummary("Create was unsuccessful.
Please correct the errors and try again.") %>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Title">Title:</label>
<%= Html.TextBox("Title") %>
<%=
Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="Director">Director:</label>
<%= Html.TextBox("Director") %>
<%=
Html.ValidationMessage("Director", "*") %>
</p>
<p>
<label for="Remark">Remark:</label>
<%= Html.TextBox("Remark") %>
<%=
Html.ValidationMessage("Remark", "*") %>
</p>
<p>
<input type="submit"
value="Create" />
</p>
</fieldset>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
复制代码
(2) Controller中Create Action代码
对应的Create
Action代码如下,我们通过UpdateModel来进行Movie类的填充,而是直接创建了一个Movie类的实例(我直接在Controller的Action中验证参数,虽然我知道这样做不对,这里只是个例子。):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
复制代码
(3) 运行结果
大家可以下载代码运行,结果如下:当不输入参数,提交表单时,我们希望这个时候能够提示“Title 不能为空!”和“Director
不能为空!”。但是,很不幸,报错了。
public ActionResult Create(FormCollection collection)
复制代码
大家可以下载代码,运行:当不输入参数时,提示“Title 不能为空!”和“Director
不能为空!”,一切正常。
[align=center]
public ActionResult
Create(string Title,string
Director,string Remark){}[/align]
[align=left] [/align]
[align=left]复制代码[/align]
那不会出现问题。因为当传递的是类或者参数时,默认的ModelBinder除了会实例化Movie类并匹配属性或给参数赋值外,还会根据键值填充ModelState集合,就像UpdateModel会帮你做这件事情一样。
6、 小结
(1) Controller中的ModelState集合是个很重要的东西,它是System.Web.Mvc.ModelState类的集合,System.Web.Mvc.ModelState的实例会负责保存键值匹配的输入值(Value属性)、以及验证错误信息(Errors属性)。
(2) Post方式传递类参数、值参数时,会通过默认的ModelBinder来填充ModelState集合。
(3) UpdateModel方法也会填充ModelState集合。
(4) 如果使用HtmlHelper,并传递FormCollection参数,又需要通过ModelState.AddModelError添加错误验证信息,则需要调用UpdateModel方法或通过ModelState.Add方法来填充ModelState集合。
(5) 使用HtmlHelper渲染View中的控件数据的时候(主要指HtmlHelper.TextBox,其它还未研究),绑定顺序为:ModelState集合、指定值、ViewData内的数据、View中强类型Model对象对应属性的数据。
7、PS:
如果通过Asp.Net MVC 1.0做数据验证的时候,我们通常不会直接在Controller中的Action里面做,提供几个开源的工具和几篇文章:
n FluentValidation
下载地址:http://www.codeplex.com/FluentValidation
文章:/article/4753293.html
n Data Annotation Model Binder
下载地址:http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471
文章:http://www.asp.net/learn/mvc/tutorial-39-cs.aspx
或者Google 4 : Asp.Net MVC 数据验证
8、补充:
根据回复补充:
一、View模型中采用了HtmlHelper("Title",Model.Title)的方式
如果View模型中采用了HtmlHelper("Title",Model.Title)的方式,在第一次进入Create Action的时候,需要给ViewData.Model赋值,如果是Post回的Create Action,如果还需要显示这个View,也需要给ViewData.Model赋值,否则View模型中的Model为NULL,也会提示未将对象应用设置到对象值的实例”。给ViewData.Model赋值有两种方法(二选一):
1、在Create Action中给ViewData.Model赋值
ViewData.Model = new Movie() (第一次进入Create Action调用)
ViewData.Model = m(Post回Create Action时候调用,m为手动、自动或者传递参数过来的Movie对象实例)
2、返回使用带TModel参数的重载函数View(TModel)
Return View(new Movie())(说明同上)
Return View(m)(说明同上)
相关文章推荐
- Razor:从aspx到cshtml常见错误及正确书写方法
- javaEE之-------Spring中的aspectJ的应用
- iReport与JasperReport PDF中文解决
- asp.net实现负载均衡
- spring (四) aop/aspectj
- ASPNET5 诊断
- asp.net url重写
- asp.net实现负载均衡
- SpringMVC集成AOP错误:java lang classnotfoundexception org aspectj lang joinpoint
- ASP.NET MVC5 route使用
- asp.net站点500.12错误解决办法
- ASP.NET多种不同页面间数据传递的方法
- atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
- Asp.Net页面的速度瓶颈有可能是正则处理造成的
- 【ASP.NET】session与cookie的比较
- ASP.NET MVC中实现多个按钮提交的几种方法
- 【转】ASP.NET网站怎么发布web项目程序和怎么部署
- asp.net+mvc5新建控制器时出现的,运行所选代码生成器时错误
- 检测到在集成的托管管道模式下不适用的 ASP.NET 设置
- 百度地图ASP.NET使用例子