Hello World
Spiga

尽可能地使用强类型数据

2009-02-27 08:19 by 老赵, 9116 visits

我们继续来谈《最佳实践》,这次的主题便是“强类型”。

一直说C#是强类型语言,通俗地讲,便是指C#中的“变量”在开发时的类型便是明确的:String便是String,Int32就是Int32,毫无争议。强类型的好处有很多,张嘴便可随意举上几例:

  • 能够享受代码提示功能
  • 能够获得重构工具的支持
  • 能够在编译期发现更多错误
  • ……

不过C#也不是“绝对”的强类型语言,因为它也有弱类型,那就是Object。我们知道Object是所有类型的最终基类,任何类型的对象都可以使用Object来引用。可是一旦转化成Object的变量之后,代码提示便消失了;即使我们“明确”对象的确切类型,也必须通过Cast才能使用——更何况它形成了一种被“滥用”或“误用”的机会。例如一段错误代码可能会传入一个不符合约定类型的对象,那么就会造成错误。更严重的是,这样的错误可能只要在“运行时”才能被发现,编译器对此无能为力。

类似的“实践”其实很多,例如“方法尽可能接受抽象的类型,而返回具体的类型”。

ASP.NET MVC中对于“强类型”一说最典型的方面便是视图。在ASP.NET MVC中每种视图(View,Partial,Layout)都可以选择弱类型和强类型两种“基类”,两者的区别便是Model的类型。强类型视图的唯一区别便是其Model属性为范型参数所指定的类型——而弱类型则自然就是Object了。在这里我提出一个“最佳实践”:总是使用强类型的视图,并且所有数据都从Model中获取。这么做可能会在一定程度上增加了代码量,因为我们需要为每个视图建立一个Model,不过我认为这是值得的。在强类型的视图中,VS中能够对Model的各种成员做出丰富的代码提示,我们便可以快速地输入代码,并确保不会出现“拼写”之类的低级错误。如果使用了ViewData这个弱类型的字典,那么每次我们获取某个值之后,都必须将其Cast成具体的类型才能使用,这无疑使视图模板变得复杂而难以维护。

其实以上的准则还有另一个层面的内容。使用项目模板安装了ASP.NET MVC之后,在~/Views/Shared/LogOnUserControl.ascx文件中可以发现对Page.User属性的直接访问。这自然可以运行,但是其带来的后果是“弱化”了aspx/ascx/master文件的“模板”概念,而重新让其意识到“我是一张页面”。在ASP.NET MVC框架中,我们要时刻记着“项目中没有页面”,我们始终使用Controller中的Action方法来处理请求,而每个请求需要对应一个磁盘上“物理文件”的思维方式一定需要改变(无论是在用WebForms模型还是MVC模型)。直接访问Page.User属性也使我们很难为视图进行独立的单元测试,因为视图与HttpContext直接耦合,而HttpContext的Mock相当困难。

在《最佳实践》的示例中,我为每个视图都构建了一个Model,它们都在MyMvcDemo.Web.UI.Models项目中。值得一提的是,由于业务的需要,视图之间很可能出现“数据共享”。例如View和Layout(更ASP.NET的说法是Page与Master Page)之间共享同一个Model。更进一步,两者之间其实是多对多的关系,如果我们为每个ViewPage定义了强类型的Model,又如何应对同一个ViewPage套用不同ViewMasterPage的情况呢?这个问题最自然的解决方式便是使用接口。一个Model对象不可以有多个父类,但是完全可以实现多个接口。因此,我们往往为强类型的ViewMasterPage指定一个接口作为其泛型参数。从示例中您也可以发现,Site.Master的类型为ViewMasterPage<ISiteMasterModel>,而每个ViewPage的Model类型都实现了ISiteMasterModel接口。

使用ViewData的另一个坏处是必须使用字符串作为键进行访问。字符串是什么?是常量。分散在各处的常量是维护性的大敌,而使用ViewData则几乎无可避免地将字符串常量分散在控制器和视图两个地方——您可能会觉得,使用枚举不就解决这个问题了吗?如果这么做,相当于为每个视图定义不同的枚举类型,那么我们为什么不直接构造强类型的Model呢?使用字符串作为键的另一个坏处是无法在编译期发现问题:如果您一不小心拼写错误了怎么办呢?您可能会觉得,原本aspx就必须到运行时才会动态编译,不过现在ASP.NET MVC的模板已经增加了相关的MSBuild Task,或者使用ASP.NET的预编译功能,都可以在编译时对视图进行检查了。这也是我建议大家使用aspx,而不是另一种DSL来构建视图的原因——aspx的周边支持实在是太丰富了。

不过在视图中,字符串常量并非只出现在ViewData的访问上。例如,使用ASP.NET MVC框架模板创建项目之后,Site.Master中生成导航栏链接的代码是这样的:

<ul id="menu">              
    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
    <li><%= Html.ActionLink("About", "About", "Home")%></li>
</ul>

代码使用了Html.ActionLink这个辅助方法生成一个导向至某个Action的链接,只可惜这里又出现了字符串参数表示的Controller名和Action名。事实上,如果您下载了ASP.NET MVC RC的源代码之后,能够发现其中的MvcFutures项目中包含了“强类型”的ActionLink辅助方法,于是我们的代码就能修改为如下模样(参见《最佳实践》的示例):

<li><%= Html.ActionLink<HomeController>(c => c.Index(), "Home") %></li>
<li><%= Html.ActionLink<HomeController>(c => c.About(), "About") %></li>
<li><%= Html.ActionLink<AccountController>(c => c.Register(), "Register") %></li>
<li><%= Html.ActionLink<AccountController>(c => c.List(1), "Admin") %></li>

这下我们便可以使用Lambda Expression这个强类型的表示方法来“告诉”ActionLink方法究竟该生成导向至哪个Action方法的链接。甚至我们可以在“调用”Action方法的同时指定其参数——例如最后一行代码,指定将查看“第一页”内容,而这些数据在交给URL Routing的配置后便能得到我们想要的URL。MvcFutures中还定义了其他类似的辅助方法,例如UrlHelper中的辅助方法则会直接生成一个URL链接——而不是一个<a />元素。可惜目前MvcFutures中的这些辅助方法编写的并不完全“正确”,因为它直接把方法名作为Action的名称来使用,而ASP.NET MVC从某个预览版开始引入了ActionNameAttribute,可以为一个Action方法指定一个不同的Action名称。因此如果您使用ActionNameAttribute来改变Action名,则很可能您需要构建自己的辅助方法。不过这条准则依旧成立:使用强类型的表示法生成URL地址

如果您要使用MvcFutures中的内容,则必须自行编译MvcFutures项目。有一点值得注意,如果您使用直接编译ASP.NET MVC RC解决方案所得到的Microsoft.Web.Mvc.dll,就会发现它依赖的是“System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”,而您开发时所使用的,也就是安装在系统中的程序集是“System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35”,两者不同自然难以兼容。幸运的是,您只要手动修改一下MvcFutures项目的程序集引用就可以了,对您来说这一定不是问题。

看到这里,不知道您是否发现了一个比较“严重”的问题,其严重程度大大降低了这些负责生成URL的辅助方法的可用性。这是个什么问题呢?又该如何解决呢?我在这里先卖个关子,下个星期我将公布这个问题,以及它的解决方法——这部分内容并没有包含在上次《最佳实践》的讲座中,算是一个“保留节目”吧。:)

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

72 条回复

  1. Anytao
    *.*.*.*
    链接

    Anytao 2009-02-27 02:02:00

    做你沙发了:-)

  2. 徐少侠
    *.*.*.*
    链接

    徐少侠 2009-02-27 03:35:00

    强类型就是好
    呵呵

    用strongTypeDataSet的感觉不是一点点爽

  3. 老赵
    admin
    链接

    老赵 2009-02-27 08:32:00

    @徐少侠
    比DataSet要爽多了,虽然我还是不喜欢DataSet。

  4. RawMan
    *.*.*.*
    链接

    RawMan 2009-02-27 08:40:00

    不错不错

  5. Selfocus
    *.*.*.*
    链接

    Selfocus 2009-02-27 08:43:00

    被VS宠坏了,所以至今我也没弄明白Javascript中的“高级应用”是咋回事

  6. 青羽
    *.*.*.*
    链接

    青羽 2009-02-27 08:43:00

    占个位置慢慢看~~

  7. zeus2
    *.*.*.*
    链接

    zeus2 2009-02-27 08:46:00

    想想现在的程序员离开了开发环境还能写程序不

  8. 老赵
    admin
    链接

    老赵 2009-02-27 09:05:00

    @zeus2
    不依赖,不离开

  9. 老赵
    admin
    链接

    老赵 2009-02-27 09:05:00

    @Selfocus
    这和VS有什么关系,JS的支持又不好

  10. jisen007[未注册用户]
    *.*.*.*
    链接

    jisen007[未注册用户] 2009-02-27 09:12:00

    不错!

  11. 紫色永恒
    *.*.*.*
    链接

    紫色永恒 2009-02-27 09:15:00

    老赵。。好山寨的标题啊。。。

  12. 老赵
    admin
    链接

    老赵 2009-02-27 09:18:00

    --引用--------------------------------------------------
    紫色永恒: 老赵。。好山寨的标题啊。。。
    --------------------------------------------------------
    啥叫山寨的标题呀?

  13. 顺便说一句[未注册用户]
    *.*.*.*
    链接

    顺便说一句[未注册用户] 2009-02-27 09:19:00

    zeus2
    -------------------
    有点无谓的担忧。有更加简单的方式来开发,我们为什么不用?就像有了JAVA、C#等语言,就几乎再没有人用汇编来写一个管理系统一样。

  14. ajax+u[未注册用户]
    *.*.*.*
    链接

    ajax+u[未注册用户] 2009-02-27 09:28:00

    --引用--------------------------------------------------
    zeus2: 想想现在的程序员离开了开发环境还能写程序不
    --------------------------------------------------------
    建议你用notoboke 写一个erp出来,呵呵!

  15. 未登陆的YAO㊣[未注册用户]
    *.*.*.*
    链接

    未登陆的YAO㊣[未注册用户] 2009-02-27 09:33:00

    @zeus2
    用c++做开发应该可以吧,.net真没试过,没了vs我还真不知道怎么用.net开发网站,谁知道国外没钱买vs的.net程序员日子怎么过的?

  16. kiler
    *.*.*.*
    链接

    kiler 2009-02-27 09:38:00

    @未登陆的YAO㊣
    你不知道vs有免费版吗?还有学生用的话是不要钱的。

  17. 未登陆的YAO㊣[未注册用户]
    *.*.*.*
    链接

    未登陆的YAO㊣[未注册用户] 2009-02-27 09:50:00

    --引用--------------------------------------------------
    kiler: @未登陆的YAO㊣
    你不知道vs有免费版吗?还有学生用的话是不要钱的。
    --------------------------------------------------------

    kiler可以思考一下 “免费版,学生不要钱” 的目的是什么?

  18. 退尽浮华,尽显本色
    *.*.*.*
    链接

    退尽浮华,尽显本色 2009-02-27 09:58:00

    强类型似乎对需求相对很明确的项目来说有很大的益处。但就目前绝大部分中小企业,他们接的项目大概在10W一下,这类客户往往业务要求不太明确,我们中小企业对需求调研、概要设计又不太重视,双方都想花最少的人力物力尽快完成。往往等项目成型后,客户说这里不好,那里需要改。不得不修改数据库,强类型在这里似乎很尴尬。

  19. kiler
    *.*.*.*
    链接

    kiler 2009-02-27 10:03:00

    @未登陆的YAO㊣
    需要思考吗,不就是以后等你在大的商业项目里用他的产品嘛,项目大了,花点钱用商业产品很正常,没什么大不了的。项目小,没钱就用免费版,没什么大不了的。天下没有免费的午餐,总想着免费那也就只能局限于做点小东西。

  20. 重典
    *.*.*.*
    链接

    重典 2009-02-27 10:12:00

    @Jeffrey Zhao
    手太快,不人道

    我感觉强类型的稳定性比较强,但是仅限于稳定的软件中,如果软件时常更改
    如Viewdata返回类型中删除字段

    如果是强类型,则报编译错误,也就是更改Controller时就要更改View

    如果使用 ViewData[""]获取,可以写扩展方法先检测其存在,
    Get(ViewDataDictionary v,string key){return v.Contains(key)?v[key]:new object();}
    这样即便更改Controller的话对于View也没有影响, 不必重复工作,



    所以最佳应该是漂在前提条件下的,对于需求朝令夕改的网站来说,更改好的向前向后兼容性可能更佳


    小言一下,望 Jerry Zao(刚刚从另个帖子学来的) 讨论一番

  21. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2009-02-27 10:15:00

    好一阵没有关注 asp.net mvc 了,记得 rails 里推荐尽量不要用 ActionLink 这样的辅助方法,原因是 performance. 不知道 asp.net mvc 里是不是也类似?

  22. 老赵
    admin
    链接

    老赵 2009-02-27 10:18:00

    @木野狐(Neil Chen)
    理论上Helper的性能肯定要低,事实上……我有机会仔细看看会不会有性能瓶颈。当然,从目前的代码上看,每次都要对expression tree做compile,看起来不是很爽,我在设法找一些好地解决方案。

  23. 未登陆的YAO㊣[未注册用户]
    *.*.*.*
    链接

    未登陆的YAO㊣[未注册用户] 2009-02-27 10:18:00

    --引用--------------------------------------------------
    kiler: @未登陆的YAO㊣
    需要思考吗,不就是以后等你在大的商业项目里用他的产品嘛,项目大了,花点钱用商业产品很正常,没什么大不了的。项目小,没钱就用免费版,没什么大不了的。天下没有免费的午餐,总想着免费那也就只能局限于做点小东西。

    --------------------------------------------------------

    就算通过Open License武装一个vsts团队,我觉得也挺吓人的

  24. 老赵
    admin
    链接

    老赵 2009-02-27 10:20:00

    @重典
    你那是掩盖错误,不是纠正错误。没有合适的key对应的value,就算不在Get时出错,也会在Cast和使用时有问题。 我认为朝令夕改不是靠ViewData的弱类型来能解决问题的,反而是强类型能暴露出更多问题,及早改变。

  25. 重典
    *.*.*.*
    链接

    重典 2009-02-27 10:25:00

    @Jeffrey Zhao
    使用时最多是逻辑不对,但只在有必要时修改View
    而不是像强类型一样修改Controller就修改View,这样成本太大

    Cast也只是在Controller里做,View里不会做所以 也应该没什么问题

  26. 老赵
    admin
    链接

    老赵 2009-02-27 10:28:00

    @重典
    View里是读取ViewData的地方,不Cast怎么会正确?
    就算不用强类型,遇到修改的时候还是必须同时修改Controller和View的。两者的区别只是操作字典,还是操作特定类型上吧。

  27. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2009-02-27 10:35:00

    @Jeffrey Zhao
    谢谢. 我在想 rails 里因为用的 ruby,是解释型,所以对调用的性能可能比较关注。而 .net 中用编译的,可能要好点。所以这个我也不确定 rails 的 best practice 是否适合于 asp.net mvc. 目前也没有时间去研究这些,只好多关注你的 blog 了。

  28. 重典
    *.*.*.*
    链接

    重典 2009-02-27 10:37:00

    @Jeffrey Zhao
    嗯,我感觉我应该亲身体验一下。。。。

    我试着在项目上全部使用一下强类型。

    谢谢Jerry Zhao^^





  29. 海洋——海纳百川,有容乃大.
    *.*.*.*
    链接

    海洋——海纳百川,有容乃大. 2009-02-27 10:38:00

    支持使用强类型!

  30. 老赵
    admin
    链接

    老赵 2009-02-27 10:49:00

    @重典
    好啊好啊,呵呵

  31. 老赵
    admin
    链接

    老赵 2009-02-27 10:50:00

    @木野狐(Neil Chen)
    设计的practice大都可以运用,其他的……要具体情况具体分析了……

  32. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:05:00

    @Jeffrey Zhao
    不知道杰瑞赵把没把ASP.NET MVC应用的实际项目中呢

    我从PV2就应用了几个,最近一个站点的ASP.NET MVC性能

    日9K来的IP的站
    Asp.net MVC + Linq2SQL +SQL2005EXPRESS
    网站用户少全数据操作比较多,猛的时候一秒90来次查询

    ASP.NET MVC前台部分使用缓存+GZIP+动态部分JS输出
    后台部分没怎么处理,不过问题都是出在后台中

    主要问题出在2点上,
    1是频繁用了JSON服务器端解析,有时候出问题
    2是数据有些是实时统计,比较费CPU,数据写入也挺频繁,不过还算挺快

    其它的没有遇到明显问题

  33. 老赵
    admin
    链接

    老赵 2009-02-27 11:12:00

    @重典
    尝试改写过我的衣橱一小部分,没有大规模用。
    为什么会有那么多查询,和IP数不对应啊。
    从性能上说,框架不会成为性能瓶颈的,无论asp.net mvc还是webforms都不例外。

  34. mFrog
    *.*.*.*
    链接

    mFrog 2009-02-27 11:13:00

    赵老师,我想问个问题,不知道能提供一个解决思想给我不
    现在在改公司以前做的系统。在做页面返回的时候有个问题。
    项目之前做的时候,每个功能点都做了一个页面,比如说人员的管理,首先出来的是所有的人员信息,点击个人的时候会进到个人的详细信息。个人详细信息可以修改。但是点修改的时候会进到另外一个页面,也就是我前面所说的,每个功能点有个页面。现在的问题是,我修改完了。再从我的个人详细信息点返回的时候,会返回到我修改时候的页面,这样就有问题了

    另外回退以后还要保持以前的查询状态

    请问这样问题有什么好的解决方案没?

    谢谢啦

  35. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:16:00

    @Jeffrey Zhao
    因为网站填充数据,是雇用兼职外包人员来录入的
    外包人员大概日常在线有四五百个,还要对他们录入的统计所以就形成了这个IP,这个数据量

  36. 第一控制.NET
    *.*.*.*
    链接

    第一控制.NET 2009-02-27 11:19:00

    基本做到了。。。

  37. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:20:00

    @mFrog
    我代杰瑞回答一下:

    如果不是一个页
    可以通过QueryString传递数据
    可以用Session或者Cookie

  38. 第一控制.NET
    *.*.*.*
    链接

    第一控制.NET 2009-02-27 11:21:00

    还有,不是说2月就要rtm么?还最后一天了。。。

  39. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:24:00

    @第一控制.NET
    是有这一说,可能aspnet忘记了2月28天的事了。。。

  40. mFrog
    *.*.*.*
    链接

    mFrog 2009-02-27 11:24:00

    --引用--------------------------------------------------
    重典: @mFrog
    我代杰瑞回答一下:

    如果不是一个页
    可以通过QueryString传递数据
    可以用Session或者Cookie

    --------------------------------------------------------

    始终都在一个浏览器中,只是页面在转,返回还保存状态,把查询条件保存在
    Session中?或者SQL?如何返回的时候页面再加载SQL?

  41. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:27:00

    @mFrog
    最好还是用QueryString这样就可以先判断
    if(ispostback){
    if(Request.QueryString[xx]){
    构造查询
    }else
    如果不存在就显示默认

    }

  42. mFrog
    *.*.*.*
    链接

    mFrog 2009-02-27 11:31:00

    --引用--------------------------------------------------
    重典: @mFrog
    最好还是用QueryString这样就可以先判断
    if(ispostback){
    if(Request.QueryString[xx]){
    构造查询
    }else
    如果不存在就显示默认

    }
    --------------------------------------------------------
    好像你把我的意思理解错了,我现在是修改完以后返回到我原来进来查询页面,但是返回的时候,这个页面还要保存我开始的查询条件,也就是呈现出来的是我开始选择查询条件以后查询的结果。

  43. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:34:00

    1.查询页的修改连接可以 追加QueryString 将查询信息传到修改页


    2.修改页将得到的修改信息再拼到 返回连接上

    这样再加上上面的不能就达到需求了么?

  44. 老赵
    admin
    链接

    老赵 2009-02-27 11:42:00

    --引用--------------------------------------------------
    第一控制.NET: 还有,不是说2月就要rtm么?还最后一天了。。。
    --------------------------------------------------------
    改3月了

  45. 老赵
    admin
    链接

    老赵 2009-02-27 11:43:00

    @重典
    你们慢慢聊。:)

  46. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:49:00

    @Jeffrey Zhao
    快枪赵,杰瑞赵很无奈,呵呵

  47. 重典
    *.*.*.*
    链接

    重典 2009-02-27 11:50:00

    @重典
    吃饭了。。

  48. Angel Lucifer
    *.*.*.*
    链接

    Angel Lucifer 2009-02-27 11:55:00

    没看到有人从语言机制和编译器层次来解释强类型,遗憾。楼上诸位评说的好处只是强类型带来的附加值,呵呵。

    PS:发现Web前端技术人员居多(笑).

  49. 老赵
    admin
    链接

    老赵 2009-02-27 11:55:00

    @重典
    不无奈啊,我很喜欢讨论的,呵呵。

  50. 老赵
    admin
    链接

    老赵 2009-02-27 11:56:00

    @Angel Lucifer
    这就是语言的使用者(或者说业务的实现者)和语言设计者关注点的不同。
    这里知道使用强类型的好处就可以了,讨论语言机制阿编译器阿在这里没有太大必要,呵呵。

  51. Angel Lucifer
    *.*.*.*
    链接

    Angel Lucifer 2009-02-27 12:02:00

    @Jeffrey Zhao
    嗯,这点非常赞同。

  52. mFrog
    *.*.*.*
    链接

    mFrog 2009-02-27 16:10:00

    --引用--------------------------------------------------
    重典: 1.查询页的修改连接可以 追加QueryString 将查询信息传到修改页


    2.修改页将得到的修改信息再拼到 返回连接上

    这样再加上上面的不能就达到需求了么?
    --------------------------------------------------------

    我不是很明白
    赵老师能帮我解决下不?

  53. 第一控制.NET
    *.*.*.*
    链接

    第一控制.NET 2009-02-27 17:20:00

    原来rtm跳票了阿。那我也多wow几天吧。。。

  54. lotsbug[0][未注册用户]
    *.*.*.*
    链接

    lotsbug[0][未注册用户] 2009-02-27 21:00:00

    --引用--------------------------------------------------
    mFrog: --引用--------------------------------------------------
    重典: 1.查询页的修改连接可以 追加QueryString 将查询信息传到修改页


    2.修改页将得到的修改信息再拼到 返回连接上

    这样再加上上面的不能就达到需求了么?
    --------------------------------------------------------

    我不是很明白
    赵老师能帮我解决下不?
    --------------------------------------------------------
    我来凑凑热闹,有一个最简单的办法,不需要.net
    window.history.go(-1)

  55. 梁逸晨
    *.*.*.*
    链接

    梁逸晨 2009-02-28 08:44:00

    老赵,你换照片啦,另附两点: JSON是个好东西,可惜不是强类型 相比MVC,我还是比较偏向于XSLT

  56. 老赵
    admin
    链接

    老赵 2009-02-28 23:36:00

    @梁逸晨
    好吧,虽然我觉得xslt从易用性,性能,以及周边的辅助功能开发都比较“特别”。

  57. webtoy
    *.*.*.*
    链接

    webtoy 2009-04-25 19:21:00

    这里有几篇关于asp.net mvc性能优化的文章,推荐大家看一下,讨论一下:

    ASP.NET MVC Performance
    http://blog.whiletrue.com/2009/04/aspnet-mvc-performance/

    基于表达式树的 ActionLink 辅助方法的性能启示
    The performance implications of the expression tree-based ActionLink helper
    http://codeclimber.net.nz/archive/2009/04/17/the-performances-implications-of-the-expression-tree-based-actionlink-helper.aspx

    如何优化 asp.net mvc web应用程序的性能
    http://codeclimber.net.nz/archive/2009/04/17/how-to-improve-the-performances-of-asp.net-mvc-web-applications.aspx

  58. 老赵
    admin
    链接

    老赵 2009-04-25 21:20:00

    @webtoy
    看了,不过感觉除了可以推而广之的准则,针对ASP.NET MVC的性能优化都不是瓶颈……不过这很正常,很少又因为程序或框架成为瓶颈的。

  59. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-05-21 15:32:00

    俄。。。 好像MvcFutures的东西没有加入1.0正是版阿。。。

  60. 应少
    *.*.*.*
    链接

    应少 2009-07-27 16:29:00

    “总是使用强类型的视图,并且所有数据都从Model中获取”

    感觉回到了.aspx .aspx.cs了,应该是只为需要的几个页面建立ViewModel,如果为每个页面建立ViewModel,不但增加了代码量,维护起来更是让人头疼的。。

  61. 老赵
    admin
    链接

    老赵 2009-07-27 16:32:00

    @应少
    一个页面一个ViewModel,这也叫多?
    当你每个页面都是弱类型的,稍作修改,那才叫头疼。
    MVC,“M”是重要的一部分,这可省不得。

  62. 应少
    *.*.*.*
    链接

    应少 2009-07-27 17:02:00


    To:Jeffrey Zhao


    我也在从webForm转到MVC的实践中,问个问题:

    如果我一个页面,有十几处显示同一类型的列表数据(如:显示不同种类的新闻列表),那我这个页面(通常是首页)的Model该如何写呢?

    是不是只放一个获取列表的方法(如从BLL中的GetList方法)作为属性放进来,然后在aspx视图中传不同的参数,获取不同的列表?

    你总不能让我在这个ViewModel中写几十个属性吧(我这个页面,加起来可能有几十个实体,且不谈这个网站适不适合用MVC)



  63. 老赵
    admin
    链接

    老赵 2009-07-27 17:42:00

    @应少

    public class MainModel
    {
       public List<Article> Articles{get;set;}
       ...
    }
    

    写几十个属性也很正常啊,否则你也是用几十个Magic String作字典的key,不是吗?

  64. 应少
    *.*.*.*
    链接

    应少 2009-07-28 17:15:00

    那样写太幸苦了。我还是用泛型吧。我写了三个泛型,具体的强类型在视图继承处或视图中调用时指定,为每个视图指定一个viewModel。。实际上是将UI逻辑分成了两块(视图上有什么,viewModel中就要指定,完了还得在视图中调用)。。这样做反而降低了内聚,增加了代码维护量。。个人观点。。

  65. 老赵
    admin
    链接

    老赵 2009-07-28 18:37:00

    @应少
    啥叫“用范型”?

  66. 应少
    *.*.*.*
    链接

    应少 2009-07-29 09:06:00

    @Jeffrey Zhao

    比如我有五个视图,分别显示:产品列表,新闻列表,会员列表,软件列表,图片列表..

    按老大的说法,是要建五个viewModel?而且意义仅仅是一句列表属性:如: public List<Product>{get;set;};如此重复的工作有嘛意义呢?


    我的意思是只建一个泛型列表类就行了,如:

    public class ListModel<T> where T : class
    {
    public IList<T> List { get; set; }
    }

    然后在继承的页面:
    System.Web.Mvc.ViewPage<ListModel<Product>>

    还有一种情况,页面上有多种数据列表或单篇详情,就用一个哈希表或字典来维护这些列表。具体的强类型不在继承处指定(在继承处指定字典或哈希表的强类型),而在aspx视图中循环显示时,用泛型方法来指定强类型..

    功能是实现了,即使用了强类型,在页面上全是具体的实体类可以用,又节约了代码量,维护起来方便点,老赵你看觉得哪有问题吗??待指教!

  67. 老赵
    admin
    链接

    老赵 2009-07-29 10:07:00

    @应少
    你的做法就是我说的做法,我说的是使用“强类型”,没有说一定要使用“自定义类型”。
    如果需求真像你说的那么简单,那么我连ListModel<T>都不会使用,直接用List<T>作Model了。
    但是实际情况下,几乎每个页面都是有很多功能的,例如当前用户认证信息,相关XX,查询条件。
    最常见的例子,你去看看淘宝的无论是列表页还是详细页,这种功能没法不用复杂对象做Model。

    至于你说的哈希表,就是我要避免的,除非这个Model本身从概念上就是一个字典。
    否则你使用字典来存储,一旦遇到增加删除修改一个key,在缺乏静态检查的时候就是个灾难。
    例如dict["ProductName"]忽然要改成dict["Name"]了,怎么办?

  68. OONESOFT
    *.*.*.*
    链接

    OONESOFT 2010-01-21 14:50:00

    我是初学,我想问一下Jeffrey Zhao,我现在做一个项目想用Asp.Net MVC RC2+MySQL, 使用“强类型”ViewModel显示数据非常好,我能不能这样实现,比如有单独建立一个类叫MyView,里边包含:
    public List<Article> Articles{get;set;}
    public List<User> Users{get;set;}
    public List<Product> Products{get;set;}

    public Article ArticleItem{get;set;}
    public User UserItem{get;set;}
    public Product ProductItem{get;set;}
    将所有的列表数据和单个对象都当成MyView的属性
    然后我的所有显示数据的页面都写成System.Web.Mvc.ViewPage<MyDemo.Models.MyView>
    这样的话在任何一个用到多个对象或列表的页面,实例化MyView的时候,我相应的给MyView属性赋给不同的值,这样做法不知道可不可以,是否合理?

  69. 月光疾风
    222.66.183.*
    链接

    月光疾风 2010-04-27 19:39:02

    否则你使用字典来存储,一旦遇到增加删除修改一个key,在缺乏静态检查的时候就是个灾难。 例如dict["ProductName"]忽然要改成dict["Name"]了,怎么办?

    通常来说这是不应该改的,字段名具有接口意义。我觉得强类型的意义是在于数据库结构本身具有稳定性的那种才应该是强类型。

    如果现在假设你要和连接一个系统,和这个系统有各种各样的交互,交互过程传递各种各样的数据,这些数据通常是采用XML定义,字段名称以及意义通过文档的形式暴露给你,难道这个时候你会为每一种交互的数据定一个对应的类型,很显然这个时候FieldMap这种动态数据结构才是方便的。

  70. 月光疾风
    222.66.183.*
    链接

    月光疾风 2010-04-27 19:50:40

    我上面写错了,不是数据库结构,而是数据结构,我觉得老赵可能客户端系统写的比较少,一个客户端系统连接某个服务器,这个服务器如何和这个客户端系统沟通,如果通过某个文本形式,那么客户端系统为这这些和服务器交流传递的数据结构定义强类型实在没有必要。因为服务器和客户端的约定是协议,不能轻易改变的。当然FieldMap这种动态数据结构在处理的时候,相对的防御压力也会多一点。

    FieldMap fm = new FieldMap("Bond").putField("id", "060001").putField("name", "06国债01"); 
    

    看起来FieldMap简洁许多,毕竟一个是静态定义一个是动态构建,一个强类型一个弱类型。 假设现在要为Bond这个类型加入发行价格和发行日期这两个属性,这时候定义类时我们将会陷入一个考量,定义什么类型,比如发行日期我们定义Date呢还是字符串?价格定义double呢还是字符串?对于拿日期来做计算或比较的,显然定义Date更合理,如果拿来是显示的显然某种格式的字符串更合适。无论你怎么定义在遇到不同场景时,必然要来回折腾转换,极为不便。 那FieldMap如何处理这样的问题呢?

    假设某个Field是发行日期,它的name是iDate,像下面这样我们拿到的是什么?

    fieldMap.getField("iDate").getValue();  
    

    答案是构造这个FieldMap时放的什么值就是什么值,比如有可能是yyyyMMdd格式的日期字符串,有可能是java的Date类型,如果你仅仅调用getValue(),那么你得到的是当初放的那个值,但是因为你知道这个Field叫iDate,里面的值一定是个日期,所以你有时候说我希望要拿Date,有时候希望要拿某种格式的字符串。因此你不仅仅可以调用Field的getValue(),你还可以这样:

    fieldMap.getField("iDate").getDateValue();  
    fieldMap.getField("iDate").getDateStringValue();  
    fieldMap.getField("iDate").getDateStringValue("yyyy/MM/dd");  
    

    第一个你将直接拿到Date类型,第二个你将拿到yyyy-MM-dd格式的字符串,第三个你将拿到你自定义格式的日期字符串,比如这里就是yyyy/MM/dd。 很明显看到这里我们发现FieldMap灵活便利的多,因为即使对于同一个类型,它也有很多不同的形式。

  71. 小河
    218.241.188.*
    链接

    小河 2010-09-17 18:41:10

    Resource表,RoleResource表。两表关联查询,按照你说的强类型,我的这个查询方法怎么改成是强类型的查询方法呢?代码如下:

    List<Resource> listselectresource =
        (from ur in db.RoleResource
         join r in db.Resource on ur.ResourseId equals r.ResourceId
         where ur.RoleId == roleId
         && r.Status == (int)Status.Nomal
         orderby r.CreateTime descending
         select r).ToList();
    
  72. 老赵
    admin
    链接

    老赵 2010-09-17 21:08:15

    @小河

    var source = 
        (from ur in db.RoleResource
         from r in db.Resource
         where ur.RoleId == roleId
         where r.Statis == (int)Status.Normal
         order by r.CreateTime descending
         select r).ToList();
    

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我