How we (should) do MVC

How we (should) do MVC

 

1.     框架图

2.     分层结构,使用IOC解耦各层,使各层仅接口依赖。

3.     考虑在EF与服务层中间加入Repository Pattern/Unit of Work Pattern并同时使用IOC

4.     从问题域或面向对象的视角划分层内的对象,比如Service层,不要把所有的服务接口定义及实现放入唯一类或文件中,而是需要划分。

5.     Domain Model

5.1. Domain Model 根据需求分析从数据库角度出发使用面向对象思维采用EF Code First 方式建立POCO 类,尽量使用ID做主键,属性命名尽量符合EF惯用法,关联的需要延迟加载的类型对象使用virtual属性,集合使用ICollection.

5.2.  考虑 适当给Domain Model添加辅助方法以简化业务实现。

5.3. 考虑 适当给 Domain Model添加NotMapped属性以简化业务实现。

5.4. 考虑 适当给 Domain Model 添加外键属性以适合某些场景的应用。

5.5. 将数据约束建立在数据库表设计中,不要将UI检查约束属性放到DomainModel中,而是放到ViewModel中。

5.6. 类使用名词单数形式,集合属性使用名词复数形式。

6.     EF

6.1. 使用EF4.1 Code First

6.2. 注意单复数形式

6.3. 遵循EF惯用规则,只在惯用规则不满足需求下设置映射关系。

7.     Repository Pattern/Unit of Work Pattern

7.1. 在服务层和EF层加入Repository Pattern/Unit of Work Pattern

7.2. Repository Pattern/Unit of Work Pattern中使用接口与实现分离原则

7.3. 在服务层和本层接口间使用IOC/DI解耦紧依赖

8.     服务层

8.1. 在服务层使用接口与实现分离模式

8.2. 在服务层根据域模型面向对象地划分成多个服务,不允许全放在一个里。

8.3. 服务层调用Repository Pattern/Unit of Work Pattern层,并且使用IOC只能接口依赖,不能直接调用EF

8.4. 服务层接口函数中的多参数使用DTO模式传递,不要使用一长串参数的那种方式。DTO,数据传输对象,可以理解为ViewModel

8.5. Repository Pattern接口中使用DomainModel做参数,服务调用Repository Pattern时通过AutoMapperDTODomainModel间做转换。

8.6. 考虑 服务接口层返回ViewModel,并通过AutoMapper转换调用Repository得到的DomainModel再返回ViewModel

9.     Controller

9.1. 从资源的角度去划分Controller。既从域模型对象的视角去划分Controller,或者认为一个Controller对应一个表。

9.2. 使用Restful风格定义Action。因为从资源角度去划分Controller,那么一个Controller应该是对资源的CRUD操作的GET/Post,所以一个Controller不应该超过8Action,理想情况的Controller命名应该是“DomainModel+Controller”,包括的Action有:

public ViewResult Index() 表示Get资源集合的View

public ViewResult Details(int id)表示Get指定id的资源对象的View

public ActionResult Create()表示Get资源对象的View

[HttpPost]

public ActionResult Create(ViewModel类型 model)表示Post创建资源对象

public ActionResult Edit(int id)表示Get修改资源对象的View

[HttpPost]

             public ActionResult Edit(ViewModel类型 model)表示Post修改资源对象

              public ActionResult Delete(int id)表示Get删除指定对象的View

[HttpPost] 

            public ActionResult Delete(int id)表示Post删除指定对象

9.3. 如果一个Controller的名字不是一个域模型对象的名字或者这个ControllerAction的数量超过上面描述的8个或者它的Action名字跟上面描述的大不同,说明没有从资源的角度去划分Controller,需要重新规划Controller

9.4. 正确的明确的指定ActionHttp method,特别是对于Post

9.5. 不要 Controller中定义任何私有方法,不要有任何除Get/Post之外的同名Action的重载

9.6. Action的参数个数需要在0-2个之间。对于Action的长串多参数应该定义相应的ViewModel类并将参数作为该ViewMoel的属性,然后使用ViewModel作为参数。

9.7. 使用ViewModel作为Action的参数后,对于页面到ActionViewmodel的参数数据绑定,首先要充分利用DefaultModelBinder的绑定规则绑定,如果不能满足,需要使用自定义ModelBinder绑定参数,不要在Controller内部在对字符串参数逗号处理或列表处理之类的参数绑定方法。

9.8. Action的实现要简单,只做调度工作,既只是调用相应的服务接口并转交ViewModel给相应的View或者只检查ModelState.IsValid并调用相应的服务接口。一个Action函数里的代码应该在5行以内。

9.9. 不要 Action不要掺杂业务实现,也不应该知道view的东西,Action作为ViewService的中间人,它唯一的一个桥梁应该只有一个参数,那就是ViewModel

9.10.            Controller与服务层的依赖要使用IOC接偶,仅仅是接口依赖。

10.  ViewModel

10.1.            要从View的数据视角去定义ViewModel。注意ViewModelDomainModel是从不同的视角来定义的,DomainModel是从域模型(数据库)的角度定义的,而ViewModel是从页面数据的视角定义的,简单的说一个页面View展示或者提交的数据只有一个强类型的对象,那就是ViewModel,即一个View有且仅有一个对应的ViewModel

10.2.          View是强类型的,即一个View的所有要展示或提交的数据只对应唯一一个定义的ViewModel类型,简单的理解就是ActionView只通过一个ViewModel绑定或提交,不要使用任何ViewBagViewData等动态类型或字典来传递数据。

10.3.          View的强类型说明你应该常用这样类型的代码,GetAction中是return View(model), 相应的view中是@model ViewModel类型,而PostAction只有一个参数,也是ViewModel类型。

10.4.          ViewModel中只包含View需要的数据,并且包含View所有需要的数据。

10.5.          ViewModel中包含校验规则属性

10.6.          考虑 ViewModel中定义辅助方法封装显示逻辑,以避免在View中实现逻辑导致难以测试。

10.7.          ViewModel的属性命名要参照相应的DomainModel,如果ViewModel中的属性有对应的DomainModel中相应概念的属性,则属性名一定要和DomainModel相同。

10.8.            对于页面PostViewModel在调用服务接口前需要对该ViewModel检查ModelState.IsValid, 并且前提是要在ViewModel中定义检查规则。

 

11.  View

11.1.            View要是强类型的,一个View对应一个ViewModel,不使用ViewBag

11.2.           不要 View不要包含业务及复杂的逻辑,如果在view中出现if/循环等逻辑处理,应该考虑封装HtmlHelper来封装相应业务,否则容易出错且不易测试。

11.3.            要综合使用layout/partial view等减少重复代码及处理框架

11.4.          一个view的数据模型应该是一个域模型或相关范围内,如果一个view包含太多不太相关的数据模型,则要考虑把这个view根据模型范围拆分成多个view,再通过partial组合,否则一个太大的view对应的viewmodel难以处理。

 

posted @ 2011-08-03 16:01  邓东林  阅读(767)  评论(3)    收藏  举报