在前面的系列中,我們已經完成了資料庫設計,資料訪問和商務邏輯,接下來我們來完成前台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
首先是DTO,很簡單,這裡我們只包括需要和前台互動的屬性,而且DTO不僅可以充當MVC中的Model,還可以用在WCF中的dataContract.
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
本文著作權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。