在前面的系列中,我们已经完成了数据库设计,数据访问和业务逻辑,接下来我们来完成前台MVC和Extjs界面部分.
在这段时间里,spring.net已经发布了1.2版本,asp.net mvc也更新到了RC1 Refresh.nhibernate更新到了2.0.整个Demo程序也做了相应的更新.
整个架构由asp.net mvc把后台的业务和前台界面联系起来,在Controller中调用业务逻辑完成前台的调用,完成相应的视图转发等工作.这样存在两个问题:
Controller怎么调用业务逻辑?
最好不要直接调用业务逻辑对象,按照面向接口的编程原则,这里采用IOC依赖注入功能,把实际的业务对象注入到Controller中,这样在Controller中只是对于业务接口编程,而与具体的实现无关.如果二次开发有修改,只需要把相应的业务逻辑实现添加进来,然后修改配置文件即可.
Controller中是不是直接使用nhibernate的实体对象?
nhibernate的实体对象中包含很多复杂的一对多,多对多等映射关系,这种关系很容易造成递归调用,而且很多属性只是为了编程性添加的,而不需要其它层的开发人员知道.而且nhibernate的复杂实体对象在序列化时也并不容易,经常会造成循环引用,如果采用了Lazy Loading还可能会造成Session关闭的问题.
所以在这里引入了DTO(Data Transfer Object),用来完成和后台业务对象的相互转换.由于采用Extjs客户端,所以前台使用Json对象,这样就要完成Json和DTO的相互转换,再完成DTO和Nhibernate实体的相互转换.
下面我们就以用户User为例,我们来完成控制层部分.
1.DTO
namespace DirectCenter.DTO { [DataContract] public class UserDTO { [DataMember] public string UserID; [DataMember] public string UserName; [DataMember] public string ManagerID; [DataMember] public string ManagerName; [DataMember] public string DepartmentID; [DataMember] public string DepartmentName; [DataMember] public string CompanyID; [DataMember] public string CompanyName; [DataMember] public DateTime? ValidFrom; [DataMember] public DateTime? ValidTo; [DataMember] public string Telephone; [DataMember] public string Mobile; [DataMember] public string Email; } }
可以看到DTO中和原来NHibernate实体属性不一致.那他们两个之间怎么进行转换呢?如果每次需要转换时都去硬编码利用性差了点,如果利用反射写个帮助类来完成相应的转换灵活性差了点.所以又引入了DTOMapper来完成DTO和实体的转换.可以对于Nhibernate实体中的Department,Company这样的对象属性,怎么能够通过DTOMapper转换呢??你可以在DTOMapper中注入相应业务Manager来完成,不过那样过于复杂了.
这样我们把所有的要用到的业务逻辑接口放到AllManagerFactory中,再通过spring.net注入具体的实现,这样在任何地方获取实例是都能够获取到业务逻辑实例.
依赖注入如下:
<object id="ManagerFactory" type="DirectCenter.DTO.AllManagerFactory,DirectCenter.DTO"> <property name="UserManager" ref="UserManagerTrans"/> <property name="CompanyManager" ref="CompanyManagerTrans"/> <property name="DepartmentManager" ref="DepartmentManagerTrans"/> </object>
在AllManagerFactory中可以直接从ApplicationContext中获取到对象:
public static AllManagerFactory ManagerFactory { get { var webApplicationContext = ContextRegistry.GetContext() as WebApplicationContext; AllManagerFactory manager = webApplicationContext.GetObject("ManagerFactory") as AllManagerFactory; return manager; } }
这样我们就可以直接在UserDTOMapper中完成DTO和nhibernate对象的相互转换,不过感觉还是太复杂,硬编码太多.
public class UserDTOMapper:BaseDTOMapper { public static UserDTO MapToDTO(User model ) { UserDTO dto = new UserDTO(); dto.UserID = model.UserID; dto.UserName = model.UserName; dto.ManagerID = model.Manager == null ? "" : model.Manager.UserID; dto.ManagerName = model.Manager == null ? "" : model.Manager.UserName; dto.Mobile = model.Mobile; dto.Telephone = model.Telephone; dto.ValidFrom = model.ValidFrom; dto.ValidTo = model.ValidTo; dto.CompanyID = model.Company == null ? "" : model.Company.CompanyID; dto.CompanyName = model.Company == null ? "" : model.Company.FullName; dto.DepartmentID = model.Department == null ? "" : model.Department.DepartmentID; dto.DepartmentName = model.Department == null ? "" : model.Department.DepartmentName; dto.Email = model.Email; return dto; } public static User MapFromDTO(UserDTO dto) { User user = new User(); user.UserID = dto.UserID; user.UserName = dto.UserName; user.Manager = dto.ManagerID == null?null:ManagerFactory.UserManager.GetUser(dto.ManagerID); user.Mobile = dto.Mobile; user.Telephone = dto.Telephone; user.ValidFrom = dto.ValidFrom; user.ValidTo = dto.ValidTo; user.Company = dto.CompanyID == null?null:ManagerFactory.CompanyManager.GetCompany(dto.CompanyID); user.Department = dto.DepartmentID == null? null:ManagerFactory.DepartmentManager.GetDepartment(dto.DepartmentID); user.Email = dto.Email; user.CreateTime = DateTime.Now; return user; } }
2. Controller
这里我使用MvcContrib,使Asp.net Mvc运行在Spring.net容器中(MvcContrib里面还包含StructureMap, Windsor,NVelocity等对Asp.net Mvc的支持).这样的话,我们必须在Spring.net定义Controller对象.
<object id="UserController" singleton="false" type="DirectCenter.Controllers.UserController, DirectCenter.Controllers" > </object>
注意这里的singleton如果不设置成false的话,会由spring.net容器管理Controller,这样只存在一个实例,mvc的ControllerContext在每次请求时会不清空,导致于ModelBinder在绑定Controller参数时实际上绑定的是上次请求的同名参数的值.
同DTO一样,我们定义一个BaseController基类,在基类中加入AllManagerFactory,这样每个继承的Controller都可以直接使用业务接口.
比如用户登陆,我们就可以如下实现:(UserController.cs)
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Login(string userid, string password) { var rdto = new ResultDTO(); User user = ManagerFactory.UserManager.GetUser(userid); if (user != null && user.Password.Trim() == password.Trim()) { rdto.Message = "
登陆成功
"; rdto.Result = true; } else { rdto.Message = "
登陆失败
"; rdto.Result = false; } return this.Json(rdto); }
MVC相关的东西在这里就不多解释了,新添的JsonResult方便了返回Json格式的操作.可以看到返回的是ResultDTO对象,而不是简单的字符串,这是为了规范返回值,因为通常情况下,前台不仅需要返回值,在其它情况下,前台需要知道执行结果以及提示信息.ResultDTO就包括这执行结果,返回数据,提示信息这三个属性:
[DataContract] public class ResultDTO { [DataMember] public bool Result; [DataMember] public string Message; [DataMember] public object Data; }
这样的话,前台就可以根据ResultDTO.Result属性判断执行,True则读取Data,False则显示Message
先到这里,回家吃饭了,过会再发剩下的一篇.先发出完整的代码下载.
作者:孤独侠客(似水流年)
出处:http://lonely7345.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。