这算是ASP.NET MVC的一个大BUG吗?
这是昨天一个同事遇到的问题,我觉得这是一个蛮大的问题,而且不像是ASP.NET MVC的设计者有意为之,换言之,这可能是ASP.NET MVC的一个Bug(不过也有可能是保持原始请求数据而作的妥协)。StackOverflow上也有对这个问题的描述http://stackoverflow.com/questions/1775170/asp-net-mvc-modelstate-clear
闲话少说,我们通过一个简单的问题重新这个问题。首先我们 定义了如下一个默认的HomeController,它具有一个默认Action方法Index。该方法接受一个类型为DemoModel的参数,定义其中的逻辑非常简单:我们对该参数的三个属性略加修改后,将其作为Model呈现在对应的View中。
public class HomeController : Controller
{
public ActionResult Index(DemoModel model)
{ model.Foo += ":Changed";
model.Bar += ":Changed";
model.Baz += ":Changed";
return View("index", model);
}
}
public class DemoModel
{
public string Foo { get; set; }
public string Bar { get; set; }
public string Baz { get; set; }
}
对于Action方法Index对应的View(Index.cshtml),我们可以采用如下三种定义方式将Model对象以编译模式呈现出来。
//第一种形式
@model DemoModel
@Html.LabelFor(m=>m.Foo)
@Html.TextBoxFor(m => m.Foo)
@Html.LabelFor(m => m.Bar)
@Html.TextBoxFor(m => m.Bar)
@Html.LabelFor(m => m.Baz)
@Html.TextBoxFor(m => m.Baz) //第二种形式
@model DemoModel
@Html.LabelFor(m=>m.Foo)
@Html.EditorFor (m => m.Foo)
@Html.LabelFor(m => m.Bar)
@Html.EditorFor (m => m.Bar)
@Html.LabelFor(m => m.Baz)
@Html.EditorFor (m => m.Baz) //第三种形式
@model DemoModel
@Html.EditorForModel
现在我们运行该程序,并通过Query String的形式提供作为Action方法Index参数的数据(?foo=123&bar=456&baz=789),我们可以看到界面上呈现出来的总是原始值,也就是说我们在Action方法Index中对原始数据的修改没有起到任何效果。

通过查看ASP.NET MVC框架自身的代码,我想这个问题的根源应该源于InputExtensions类型的InputHelper方法。如下所示,当InputHelper在指定表单元素值得时候,会先从当前ModelState中获取,如果该值在ModelState中不存在,才会从当前ViewData中获取。对于本例来说,ModelState中的值是原始值,ViewData的值采用修改后的值。
public static class InputExtensions
{
private static MvcHtmlString InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes);
}
private static MvcHtmlString InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes)
{
…
switch (inputType)
{
…
default:
{
string str4 = (string) htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string));
tagBuilder.MergeAttribute("value", str4 ?? (useViewData ? htmlHelper.EvalString(fullHtmlFieldName, format) : str2), isExplicitValue);
goto Label_016C;
}
}
…
}
我觉得rinsen的评论说得有道理,这也可能是为了保持请求的原始数据而作的妥协。不过我还是觉得这样的设计有违MVC的基本原则,MVC处理请求的流程很清楚:客户端(浏览器)向定义在Controller中的某个Action方法发送请求,Action方法处理这个请求,并呈现出相应的View来对请求做最后的响应。换言之,最终呈现怎么的View应该完全由Action方法决定,对于我们的例子来说,Action方法很明显的意图就是将更新过的Model呈现出来。而且这是一种非常典型的场景:服务端对原始数据进行简单的加工后再呈现出来。
其实我觉得严格来说也是无奈之举吧,
拿Update场景来说
比如说Model里面的某个Property可能是Int的,但是你传入的Form值却可能是任意的字符串,这时后台ModelState.IsValid是false,然后你就需要返回View让用户继续修改,并把用户输入的值带入到Form中。
这时候model其实是有的(反正不为null,而Property也是有默认值的:0)而回显显然不可能回显为0,而是用户的输入。
所以这个角度看来ModelState的优先级是比较高的。
[你总不能回显一个0,然后错误提示“你输入的不是数值类型”吧]
这算是ASP.NET MVC的一个大BUG吗?的更多相关文章
- [ASP.NET MVC2 系列] ASP.Net MVC教程之《在15分钟内用ASP.Net MVC创建一个电影数据库应用程序》
[ASP.NET MVC2 系列] [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序> ...
- 在mysql中RIGHT JOIN与group by一起使用引起的一个大bug
本来按理说这个小问题不值得写一个博客的,不过正是这个小问题造成了一个大bug. 本来每月对数据都好好的,但是这一两天突然发现许多数据明显不对,这一块的代码和sql有些不是我写的,不过出现了bug,还是 ...
- 【教训】null == '',改造ThinkSNS 系统里面的一个缓存管理函数S()后,留下一个大bug
本来想简化 ThinkSNS 系统里面的一个缓存管理函数: <?php /** * 用来对应用缓存信息的读.写.删除 * $expire = null/0 表示永久缓存,否则为缓存有效期 */ ...
- 在asp.net mvc中上传大文件
在asp.net mvc 页面里上传大文件到服务器端,需要如下步骤: 1. 在Control类里添加get 和 post 方法 // get method public ActionResult Up ...
- ASP.NET MVC提交一个较复杂对象至WCF Service
前一篇<jQuery.Ajax()执行WCF Service的方法>http://www.cnblogs.com/insus/p/3727875.html 我们有练习在asp.net mv ...
- ASP.NET没有魔法——ASP.NET MVC 与数据库大集合
ASP.NET没有魔法——ASP.NET与数据库 ASP.NET没有魔法——ASP.NET MVC 与数据库之MySQL ASP.NET没有魔法——ASP.NET MVC 与数据库之ORM ASP.N ...
- [转]ASP.NET MVC Json()处理大数据异常解决方法 json maxjsonlength
本文转自:http://blog.csdn.net/blacksource/article/details/18797055 先对项目做个简单介绍: 整个项目采用微软的ASP.NET MVC3进行开发 ...
- 新的框架,新的感觉ASP.NET MVC 分享一个简单快速适合新手的框架
在ASP.NET世界中摸爬滚打好几年,用过了各种框架,在最初的ASP.NET web from 到现在的MVC 在起初的经典三层,到现在的MVC IOC 注入 . 突然发现,有些时候真不是跟风用一 ...
- asp.net mvc 4 json大数据异常 提示JSON字符长度超出限制的异常
今天客户突然过来找我说在后台添加了一篇超长的文章后,所有后台的文章都显示不出来了.后台的前端显示是用easyui的,返回的数据全是用json.根据客户的描述进行了同样的操作后,在firebug下发现a ...
随机推荐
- React-native之持久化保存----AsyncStorage
AsyncStorage AsyncStorage是一个简单的,未加密的,异步的,持久化,关键值存储系统,是全局的. iOS中存储类似于NSUserDefault,存储问plist文件存放在设备中. ...
- Agile
I think Agile development methodologies is something we get from our practice. It can be just acknow ...
- MongoDB-分片
1 分区12 分区23 路由服务器实例-mongos(客户端访问它)4 配置服务器实例-config 1 分片 cd /d D:\Test\bin1 10001 2 分片 cd /d D:\Test\ ...
- 转载:Chrome调试折腾记_(1)调试控制中心快捷键详解!!!
转载:http://blog.csdn.net/crper/article/details/48098625 大多浏览器的调试功能的启用快捷键都一致…按下F12;还是熟悉的味道; 或者直接 Ctrl ...
- 在php中定义常量时,const与define的区别?
问]在php中定义常量时,const与define的区别? [答]使用const使得代码简单易读,const本身就是一个语言结构,而define是一个函数.另外const在编译时要比define快很 ...
- javascript变量的作用域
javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象 讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...
- Android Intent Flags
Intent,顾名思义,即意图,通常用它来启动一个应用程序组件( Activity, Service, 或者 BroadCast Receiver ).在启动一个新的 Activity 时,可以通过给 ...
- windows和linux中搭建python集成开发环境IDE——如何设置多个python环境
本系列分为两篇: 1.[转]windows和linux中搭建python集成开发环境IDE 2.[转]linux和windows下安装python集成开发环境及其python包 3.windows和l ...
- 使用jQuery Uploadify在ASP.NET 上传附件
Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.Uploadify官方网址:http://www.uploadify.com/,在MVC中使用的方法可以参考 jQuer ...
- Guava Supplier实例
今天想讲一下Guava Suppliers的几点用法.Guava Suppliers的主要功能是创建包裹的单例对象,通过get方法可以获取对象的值.每次获取的对象都为同一个对象,但你和单例模式有所区别 ...