使用Model Binder绑定Action参数字段时的取舍问题
2009-09-28 13:57 Jeffrey Zhao 阅读(13004) 评论(26) 编辑 收藏 举报刚才在看代码的时候忽然发现了一件可能会成为问题的情况,而这个情况还挺隐蔽的。因此,我原本写到一半的东西就暂时停下,顺延至明天,而现在先来谈谈这个问题。这个问题就是在使用DefaultModelBinder在绑定字段时的取舍问题。而您在使用ASP.NET MVC的时候不妨也检查一下,看看有没有这方面的情况。
ASP.NET MVC的一个便利之处就在于,它可以将Route Value,Form或Query String里的数据自动构造成Actoin方法的参数。例如我们ProductController中有个叫做Create的Action方法:
[AcceptVerbs(HttpVerbs.Post)] public class ProductController : BaseController { public ActionResult Create(Product product) { var db = new DataContext(); db.InsertOnSubmit(product); db.SubmitChanges(); } }
这是一段使用LINQ to SQL向数据库中插入数据的方法,很简单,您一定也看得懂。ASP.NET MVC的DefaultModelBinder类会根据Product类型的字段,从Post过来的数据中获取一些值,然后构造一个Product对象。例如Product类型是这样定义的:
public class Product { public virtual int ProductID { get; set; } public virtual string Name { get; set; } public virtual float Price { get; set; } public virtual int ViewCount { get; set; } }
四个字段:ID、名称、价格以及浏览量。当用户访问/Product/Create页面时(不是刚才Post Only的Action,而是用于显示创建页的Action),客户端便会获得这样的form表单:
<form action="/Product/Action" method="post"> <input type="text" name="Name" /> <input type="text" name="Price" /> <input type="submit" /> </form>
当然,实际情况下这个表单是不会那么赤裸裸的,会有文字说明,会有校验逻辑等等。不过它的含义总归是向/Product/Action这个URL中Post两个字段:Name和Price,最后在服务器端执行得到的结果便是创建了一个指定了Name和Price的对象,它的ViewCount是0——为什么是0?因为客户端没有提供数据咯。
问题就在这里,既然客户端没有提供数据,于是ViewCount是0,但如果客户端提供了数据又该怎么办呢?例如,用户完全有能力在客户端多加一个字段,变成这样:
<form action="/Product/Action" method="post"> <input type="text" name="Name" /> <input type="text" name="Price" /> <input type="hidden" name="ViewCount" value="1000" /> <input type="submit" /> </form>
如此创建出的对象,它的ViewCount自然就直接是1000了。您可能会问,那么用户为什么会知道是ViewCount这个字段?我想,他应该可以从网站其他地方获取蛛丝马迹的,例如某个元素的id,例如某次请求所提交的参数等等。于是,他就可以这么一试了。
写到这儿,我忽然又想到,有些朋友在写form的时候可能会偷一下懒,省略了form的action属性,或者这样构造一个表单:
<% using (Html.BeginForm()) { %> ... <% }; %>
如此,form便会提交给当前URL。这样做的问题在于,如果用户通过/Product/Create?ViewCount=1000这样的URL来访问创建页面,这样提交后的数据也会自动填写上ViewCount。
当然这个问题很容易解决,例如在创建Product的Create方法中可以主动为product参数的属性设置默认值,或者使用ASP.NET MVC自带的机制:
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Create([Bind(Exclude="ViewCount")]Product product) { ... }
您可以为product参数加上BindAttribute标记,指定哪些字段不需要绑定(或哪些需要),这样即使客户端提交了某些字段,DefaultModelBinder也会忽略这些数据了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
2006-09-28 Sys.UI.Data.DataNavigator与Sys.UI.Data.SortBehavior