C#進階系列——DDD領域驅動設計初探(七):Web層的搭建
前言:好久沒更新部落格了,每天被該死的業務纏身,今天正好一個模組完成了,繼續來完善我們的程式碼。之前的六篇完成了領域層、應用層、以及基礎結構層的部分程式碼,這篇打算搭建下UI層的程式碼。
DDD領域驅動設計初探系列文章:
一、UI層介紹
在DDD裡面,UI層的設計也分為BS和CS,本篇還是以Web為例來說明。我們的Web採用的是MVC+bootstrap的架構。Table元件使用的是bootstrap table,之所以用它是因為它的API比較全,並且博主覺得它的風格適用於各種型別的裝置,無論是PC端還是手機端都都能很好的相容各種瀏覽器。
這裡還是貼出bootstrap API的相關地址。
二、程式碼示例
上篇完成了WCF的設計程式碼,但是具體的業務邏輯的程式碼還沒有,我們先來實現具體業務的CURD程式碼。
1、WCF程式碼
1.1 WCF服務業務介面程式碼
/// <summary> /// 許可權管理模組介面契約 /// </summary> [ServiceContract] [ServiceInterface] public interface IPowerManageWCFService { #region 使用者管理 [OperationContract] List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode); [OperationContract] DTO_TB_USERS AddUser(DTO_TB_USERS oUser); [OperationContract] bool DeleteUser(DTO_TB_USERS oUser); [OperationContract] bool DeleteUserByLamada(ExpressionNode expressionNode); [OperationContract]bool UpdateUser(DTO_TB_USERS oUser); #endregion #region 部門管理 [OperationContract] List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode); [OperationContract] DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); [OperationContract] bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); [OperationContract] bool DeleteDeptByLamada(ExpressionNode expressionNode); [OperationContract] bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); #endregion #region 角色管理 [OperationContract] List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode); [OperationContract] DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole); #endregion #region 選單管理 [OperationContract] List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode); [OperationContract] DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu); #endregion }
1.2 WCF介面實現程式碼:
[ServiceClass] public class PowerManageWCFService :BaseService, IPowerManageWCFService { #region Fields [Import] private IUserRepository userRepository { get; set; } [Import] private IDepartmentRepository departmentRepository { get; set; } [Import] private IRoleRepository roleRepository { get; set; } [Import] private IMenuRepository menuRepository { get; set; } #endregion #region Constust public PowerManageWCFService() { } #endregion #region WCF服務介面實現 #region 使用者管理 //這裡引數為什麼不直接用Expression<Func<DTO_TB_USERS,bool>>這種型別,是因為Expression不支援序列化,無法用於WCF資料的傳遞 public List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode) { Expression<Func<DTO_TB_USERS, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>(); } var lstRes = base.GetDtoByLamada<DTO_TB_USERS, TB_USERS>(userRepository, selector); return lstRes; } public DTO_TB_USERS AddUser(DTO_TB_USERS oUser) { return base.AddDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser); } public bool DeleteUser(DTO_TB_USERS oUser) { var bRes = false; try { base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser); bRes = true; } catch { } return bRes; } public bool DeleteUserByLamada(ExpressionNode expressionNode) { Expression<Func<DTO_TB_USERS, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>(); } var bRes = false; try { base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, selector); bRes = true; } catch { } return bRes; } public bool UpdateUser(DTO_TB_USERS oUser) { var bRes = false; try { base.UpdateDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser); bRes = true; } catch { } return bRes; } #endregion #region 部門管理 public List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode) { Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>(); } return base.GetDtoByLamada<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector); } public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept) { return base.AddDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept); } public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept) { var bRes = false; try { base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept); bRes = true; } catch { } return bRes; } public bool DeleteDeptByLamada(ExpressionNode expressionNode) { Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>(); } var bRes = false; try { base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector); bRes = true; } catch { } return bRes; } public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept) { var bRes = false; try { base.UpdateDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept); bRes = true; } catch { } return bRes; } #endregion #region 角色管理 public List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode) { Expression<Func<DTO_TB_ROLE, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_ROLE, bool>>(); } return base.GetDtoByLamada<DTO_TB_ROLE, TB_ROLE>(roleRepository, selector); } public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole) { return base.AddDto<DTO_TB_ROLE, TB_ROLE>(roleRepository, oRole); } #endregion #region 選單管理 public List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode) { Expression<Func<DTO_TB_MENU, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_MENU, bool>>(); } return base.GetDtoByLamada<DTO_TB_MENU, TB_MENU>(menuRepository, selector); } public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu) { return base.AddDto<DTO_TB_MENU, TB_MENU>(menuRepository, oMenu); } #endregion #endregion }PowerManageWCFService
這裡要說明一點,在通過lamada表示式查詢的方法裡面為什麼不直接用Expression<Func<DTO_TB_USERS,bool>>這種型別,而要使用ExpressionNode這種型別的變數呢?
這是因為Expression不支援序列化,無法用於WCF資料的傳遞。ExpressionNode這個物件的使用需要新增Serialize.Linq這個dll的引用,還好有我們神奇的NuGet,讓我們再也不用去網上找一大堆的dll了。
我們公用的增刪改查封裝到了BaseService這個父類裡面。
1.3 BaseService程式碼
public class BaseService { #region Fields private bool bInitAutoMapper = false; #endregion #region Construct public BaseService() { //註冊MEF Regisgter.regisgter().ComposeParts(this); } #endregion #region 查詢 /// <summary> /// 通用單表查詢方法 /// </summary> /// <typeparam name="DtoModel">DTOmodel</typeparam> /// <typeparam name="DomainModel">領域模型</typeparam> /// <param name="oRepository">需要傳過來的倉儲介面物件</param> /// <param name="selector">前端傳過來的lamada表示式</param> /// <returns></returns> public List<DtoModel> GetDtoByLamada<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); if (selector == null) { var lstDomainModel = oRepository.Entities.ToList(); return Mapper.Map<List<DomainModel>, List<DtoModel>>(lstDomainModel); } //得到從Web傳過來和DTOModel相關的lamaba表示式的委託 Func<DtoModel, bool> match = selector.Compile(); //建立對映Expression的委託 Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile(); //得到領域Model相關的lamada Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t)); List<DomainModel> list = oRepository.Find(lamada).ToList(); return Mapper.Map<List<DomainModel>, List<DtoModel>>(list); } #endregion #region 新增 public DtoModel AddDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel); oRepository.Insert(oDomain); return Mapper.Map<DomainModel, DtoModel>(oDomain); } #endregion #region 刪除 public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel); return oRepository.Delete(oDomain); } public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); if (selector == null) { return 0; } //得到從Web傳過來和DTOModel相關的lamaba表示式的委託 Func<DtoModel, bool> match = selector.Compile(); //建立對映Expression的委託 Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile(); //得到領域Model相關的lamada Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t)); return oRepository.Delete(lamada); } #endregion #region 更新 public void UpdateDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel); oRepository.Update(oDomain); } #endregion #region Private private void InitAutoMapper<DtoModel, DomainModel>() { var oType = Mapper.FindTypeMapFor<DtoModel, DomainModel>(); if (oType==null) { Mapper.CreateMap<DtoModel, DomainModel>(); Mapper.CreateMap<DomainModel, DtoModel>(); } } #endregion }BaseService
這個父類主要做了兩件事:一是MEF的初始化;二是通用增刪改查的實現。所有dto物件和領域model的對映都在這裡統一管理。
2、UI層程式碼
UI層裡面,為了更好分離程式碼,我們引入了介面程式設計的機制,引入了ESTM.Web.IBLL和ESTM.Web.BLL兩個專案,如圖:
2.1 ESTM.Web.IBLL程式碼
這個dll主要定義介面規則。
public interface IPowerManager { List<DTO_TB_USERS> GetUsers(Expression<Func<DTO_TB_USERS, bool>> selector = null); DTO_TB_USERS AddUser(DTO_TB_USERS oUser); bool DeleteUser(DTO_TB_USERS oUser); bool UpdateUser(DTO_TB_USERS oUser); bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null); List<DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null); DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null); bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); List<DTO_TB_ROLE> GetRoles(Expression<Func<DTO_TB_ROLE, bool>> selector = null); List<DTO_TB_MENU> GetMenus(Expression<Func<DTO_TB_MENU, bool>> selector = null); }
2.2 ESTM.Web.BLL程式碼
這個dll用於實現ESTM.Web.IBLL裡面的介面方法
[Export(typeof(IPowerManager))] public class PowerManager : IPowerManager { #region Fields //建立WCF服務連線物件 private ServiceReference_PowerManager.PowerManageWCFServiceClient oService = CreatePowerManagerService.GetInstance(); #endregion #region 介面實現 public List<DTO_TB_USERS> GetUsers(Expression<Func<Common.DtoModel.DTO_TB_USERS, bool>> selector = null) { return oService.GetUsers(GetExpressionNode<DTO_TB_USERS>(selector)); } public List<Common.DtoModel.DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<Common.DtoModel.DTO_TB_DEPARTMENT, bool>> selector = null) { return oService.GetDepartments(GetExpressionNode<DTO_TB_DEPARTMENT>(selector)); } public List<Common.DtoModel.DTO_TB_ROLE> GetRoles(Expression<Func<Common.DtoModel.DTO_TB_ROLE, bool>> selector = null) { return oService.GetRoles(GetExpressionNode<DTO_TB_ROLE>(selector)); } public List<Common.DtoModel.DTO_TB_MENU> GetMenus(Expression<Func<Common.DtoModel.DTO_TB_MENU, bool>> selector = null) { return oService.GetMenus(GetExpressionNode<DTO_TB_MENU>(selector)); } #endregion #region Privates //將lamada表示式轉換為可用於WCF傳遞的ExpressionNode型別 private ExpressionNode GetExpressionNode<Dto>(Expression<Func<Dto,bool>> selector) { if (selector == null) { return null; } ExpressionConverter expressionConverter = new ExpressionConverter(); ExpressionNode expressionNode = expressionConverter.Convert(selector); return expressionNode; } #endregion public DTO_TB_USERS AddUser(DTO_TB_USERS oUser) { return oService.AddUser(oUser); } public bool DeleteUser(DTO_TB_USERS oUser) { return oService.DeleteUser(oUser); } public bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null) { if (selector == null) { return false; } ExpressionConverter expressionConverter = new ExpressionConverter(); ExpressionNode expressionNode = expressionConverter.Convert(selector); return oService.DeleteUserByLamada(expressionNode); } public bool UpdateUser(DTO_TB_USERS oUser) { return oService.UpdateUser(oUser); } public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept) { return oService.AddDepartment(oDept); } public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept) { return oService.DeleteDepartment(oDept); } public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept) { return oService.UpdateDepartment(oDept); } public bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null) { if (selector == null) { return false; } ExpressionConverter expressionConverter = new ExpressionConverter(); ExpressionNode expressionNode = expressionConverter.Convert(selector); return oService.DeleteDeptByLamada(expressionNode); } }PowerManager : IPowerManager
public class CreatePowerManagerService { private static ServiceReference_PowerManager.PowerManageWCFServiceClient oPowerManagerClient = null; private static object obj = new object(); public static ServiceReference_PowerManager.PowerManageWCFServiceClient GetInstance() { lock (obj) { if (oPowerManagerClient == null) { oPowerManagerClient = new ServiceReference_PowerManager.PowerManageWCFServiceClient(); } } return oPowerManagerClient; } }
由於是採用的新增服務引用的方式引用的WCF服務,所以在這一層需要新增WCF服務的引用。在實現這部分程式碼的時候博主遇到過一個問題,在此和朋友們分享一下。由於在WCF服務的設計裡面用到了DTO物件,而在ESTM.Web.BLL這個專案裡面也要用到DTO,但是新增WCF服務引用的時候預設的是WCF服務裡面的DTO,而不是ESTM.Common.DtoModel這個專案的DTO物件,這樣就有問題了,每次如果我們需要改動下dto的內容,那麼我們就需要更新下服務引用。還好,微軟給我們選擇的機制,我們來看圖
這樣就能解決上面的問題了。
2.3 ESTM.Web程式碼
按照面向介面的機制,ESTM.Web專案是不需要新增ESTM.Web.BLL這個實現層專案引用的,通過MEF動態匯入ESTM.Web.BLL裡面的物件。我們來看程式碼:
public class PowerManagerController : BaseController { [Import] private IPowerManager PowerManager { set; get; } #region Views // GET: PowerManager public ActionResult User() { return View(); } public ActionResult Role() { return View(); } public ActionResult Menu() { return View(); } public ActionResult Department() { return View(); } #endregion #region 部門管理 public JsonResult GetDepartments(int limit, int offset, string departmentname, string statu) { //得到lamada表示式 var oLamadaExtention = new LamadaExtention<DTO_TB_DEPARTMENT>(); if (!string.IsNullOrEmpty(departmentname)) { oLamadaExtention.GetExpression("DEPARTMENT_NAME", departmentname, ExpressionType.Contains); } if (!string.IsNullOrEmpty(statu)) { oLamadaExtention.GetExpression("STATUS", statu, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetDepartments(lamada); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } public object GetDepartmentEdit(string strPostData) { var oDepartment = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_DEPARTMENT>(strPostData); if (string.IsNullOrEmpty(oDepartment.DEPARTMENT_ID)) { oDepartment.DEPARTMENT_ID = Guid.NewGuid().ToString(); oDepartment = PowerManager.AddDepartment(oDepartment); } else { PowerManager.UpdateDepartment(oDepartment); } return oDepartment; } public object DeleteDept(string strID) { PowerManager.DeleteDepartment(x=>x.DEPARTMENT_ID == strID); return new object(); } #endregion #region 選單管理 public JsonResult GetMenus(int limit, int offset, string menuname, string menuurl) { var oLamadaExtention = new LamadaExtention<DTO_TB_MENU>(); if (!string.IsNullOrEmpty(menuname)) { oLamadaExtention.GetExpression("MENU_NAME", menuname, ExpressionType.Contains); } if (!string.IsNullOrEmpty(menuurl)) { oLamadaExtention.GetExpression("MENU_URL", menuurl, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetMenus(lamada).ToList(); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } public object GetMenuEdit(string strPostData) { var oMenu = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_MENU>(strPostData); if (string.IsNullOrEmpty(oMenu.MENU_ID)) { //oMenu = MenuManager.Add(oMenu); } else { //MenuManager.Update(oMenu); } return oMenu; } public object DeleteMenu(string strID) { //MenuManager.Delete(strID); return new object(); } public object GetParentMenu() { var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "1"); //var lstRes = RoleManager.Find().ToList(); //var oRes = new PageRowData(); //oRes.rows = lstRes.Skip(offset).Take(limit).ToList(); //oRes.total = lstRes.Count; return lstMenu; ; } public object GetChildrenMenu(string strParentID) { var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "2" && x.PARENT_ID == strParentID).ToList(); //var lstRes = RoleManager.Find().ToList(); //var oRes = new PageRowData(); //oRes.rows = lstRes.Skip(offset).Take(limit).ToList(); //oRes.total = lstRes.Count; return lstMenu; ; } #endregion #region 許可權管理 public JsonResult GetRole(int limit, int offset, string rolename, string desc) { var oLamadaExtention = new LamadaExtention<DTO_TB_ROLE>(); if (!string.IsNullOrEmpty(rolename)) { oLamadaExtention.GetExpression("ROLE_NAME", rolename, ExpressionType.Contains); } if (!string.IsNullOrEmpty(desc)) { oLamadaExtention.GetExpression("DESCRIPTION", desc, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetRoles(lamada).ToList(); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } #endregion #region 使用者管理 public JsonResult GetUsers(int limit, int offset, string username, string fullname) { var oLamadaExtention = new LamadaExtention<DTO_TB_USERS>(); if (!string.IsNullOrEmpty(username)) { oLamadaExtention.GetExpression("USER_NAME", username, ExpressionType.Contains); } if (!string.IsNullOrEmpty(fullname)) { oLamadaExtention.GetExpression("FULLNAME", fullname, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetUsers(lamada).ToList(); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } public object GetUserEdit(string strPostData) { var oUser = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_USERS>(strPostData); if (string.IsNullOrEmpty(oUser.USER_ID)) { oUser.USER_ID = Guid.NewGuid().ToString(); oUser = PowerManager.AddUser(oUser); } else { PowerManager.UpdateUser(oUser); } return oUser; } public object DeleteUser(string strID) { PowerManager.DeleteUser(x => x.USER_ID == strID); return new object(); } #endregion }PowerManagerController
View頁面
<!DOCTYPE html> <html> <head> <meta name="viewport"相關推薦
C#進階系列——DDD領域驅動設計初探(七):Web層的搭建
前言:好久沒更新部落格了,每天被該死的業務纏身,今天正好一個模組完成了,繼續來完善我們的程式碼。之前的六篇完成了領域層、應用層、以及基礎結構層的部分程式碼,這篇打算搭建下UI層的程式碼。 DDD領域驅動設計初探系列文章: 一、UI層介紹 在DDD裡面,UI層的設計也分為BS和CS,本篇還是以Web為
C#進階系列——DDD領域驅動設計初探(六):領域服務
前言:之前一直在搭建專案架構的程式碼,有點偏離我們的主題(DDD)了,這篇我們繼續來聊聊DDD裡面另一個比較重要的知識點:領域服務。關於領域服務的使用,書中也介紹得比較晦澀,在此就根據博主自己的理解談談這個知識點的使用。 DDD領域驅動設計初探系列文章: 一、領域服務的引入 在《領域驅動設計:軟體核
C#進階系列——DDD領域驅動設計初探(四):WCF搭建
前言:前面三篇分享了下DDD裡面的兩個主要特性:聚合和倉儲。領域層的搭建基本完成,當然還涉及到領域事件和領域服務的部分,後面再專案搭建的過程中慢慢引入,博主的思路是先將整個架構走通,然後一步一步來新增相關元素,使架構慢慢變得豐滿。這篇打算分享下應用層的搭建。根據DDD的設計原則,應用層不包含任何領域邏輯,它主
C#進階系列——DDD領域驅動設計初探(五):AutoMapper使用
前言:前篇搭建了下WCF的程式碼,就提到了DTO的概念,對於為什麼要有這麼一個DTO的物件,上章可能對於這點不太詳盡,在此不厭其煩再來提提它的作用: 從安全上面考慮,領域Model都帶有領域業務,讓Client端引用Domain Model就意味著Client端可以繞過應用層直接完成業務邏輯的呼叫,這樣
C#進階系列——DDD領域驅動設計初探(三):倉儲Repository(下)
前言:上篇介紹了下倉儲的程式碼架構示例以及簡單分析了倉儲了使用優勢。本章還是繼續來完善下倉儲的設計。上章說了,倉儲的最主要作用的分離領域層和具體的技術架構,使得領域層更加專注領域邏輯。那麼涉及到具體的實現的時候我們應該怎麼做呢,本章就來說說倉儲裡面具體細節方便的知識。 DDD領域驅動設計初探系列文章:
C#進階系列——DDD領域驅動設計初探(二):倉儲Repository(上)
前言:上篇介紹了DDD設計Demo裡面的聚合劃分以及實體和聚合根的設計,這章繼續來說說DDD裡面最具爭議的話題之一的倉儲Repository,為什麼Repository會有這麼大的爭議,博主認為主要原因無非以下兩點:一是Repository的真實意圖沒有理解清楚,導致設計的紊亂,隨著專案的橫向和縱向擴充套件,
C#進階系列——DDD領域驅動設計初探(一):聚合
前言:又有差不多半個月沒寫點什麼了,感覺這樣很對不起自己似的。今天看到一篇博文裡面寫道:越是忙人越有時間寫部落格。呵呵,似乎有點道理,博主為了證明自己也是忙人,這不就來學習下DDD這麼一個聽上去高大上的東西。前面介紹了下MEF和AOP的相關知識,後面打算分享Automapper、倉儲模式、WCF等東西的,可是
C#進階系列——WebApi 異常處理解決方案(轉)
機制 輸出 ges 如果 但是 rom lba slist 解決 出處:http://www.cnblogs.com/landeanfen/p/5363846.html 閱讀目錄 一、使用異常篩選器捕獲所有異常 二、HttpResponseException自
大型Java進階專題(二) 軟體架構設計原則(上)
## 前言 今天開始我們專題的第一課了,也是我開始進階學習的第一天,我們先從經典設計思想開始,看看大牛市如何寫程式碼的,提升技術審美、提高核心競爭力。本章節參考資料書籍《Spring 5核心原理》中的第一篇 Spring 內功心法(沒有電子檔,都是我取其精華並結合自己的理解,一個字一個字手敲出來的)。
Go gRPC進階-TLS認證+自定義方法認證(七)
前言 前面篇章的gRPC都是明文傳輸的,容易被篡改資料。本章將介紹如何為gRPC新增安全機制,包括TLS證書認證和Token認證。 TLS證書認證 什麼是TLS TLS(Transport Layer Security,安全傳輸層),TLS是建立在傳輸層TCP協議之上的協議,服務於應用層,它的前身是SSL(S
Java中的設計模式(七):觀察者模式
name int 還要 The else 意圖 http exceptio 所有 介紹 觀察者模式是行為設計模式之一。當您對對象的狀態感興趣並希望在有任何更改時收到通知時,觀察者設計模式非常有用。在觀察者模式中,監視另一個對象狀態的對象稱為Observer,正在被監視的對象
設計模式(七):Java中的觀察者設計模式
介紹 觀察者模式是行為設計模式之一。當您對物件的狀態感興趣並希望在有任何更改時收到通知時,觀察者設計模式非常有用。在觀察者模式中,監視另一個物件狀態的物件稱為Observer,正在被監視的物件稱為Subject。 根據GoF,觀察者設計模式的意圖是; 定義物件之間的一對多依賴關係,以便當一個物件更改狀態時
設計模式(七):橋接模式
優點: ① 分離抽象介面及其實現部分。提高了比繼承更好的解決方案。 ② 橋接模式提高了系統的可擴充性,在兩個變化維度中任意擴充套件一個維度,都不需要修改原有系統。 缺點: ① 橋接模式的引入會增加系統的理解與設計難度,由於聚合關聯關係建立在抽象層,要求開發
把握linux核心設計思想(七):核心定時器和定時執行
途】 前面章節說到了把工作推後到除現在以外的時間執行的機制是下半部機制,但是當你需要將工作推後到某個確定的時間段之後執行,使用定時器是很好的選擇。 上一節核心時間管理中講到核心在始終中斷髮生執行定時器,定時器作為軟中斷在下半部上下文中執行。時鐘中斷處理程式會執行update_p
EF Code first 和 DDD (領域驅動設計研究)系列一
發的 tex bsp cti 設計 ron 映射 developer devel 在上個公司工作時,開發公司產品的過程中,接觸到了EF Code first. 當時,整個產品的架構都是Lead developer設計建立的,自己也不是特別理解,就趕鴨子上架跟著一起開發了。
【9】C++進階系列(泛型設計以及STL標準模板庫)
1、泛型程式設計基本概念 泛型程式設計:編寫不依賴與具體資料型別的程式,將演算法從特定的資料結構中抽象出來,成為通用的。C++的模板為泛型程式設計定義了關鍵的基礎。 兩個術語:概念,模型 概念:用來界定具備一定功能的資料型別,例如:將“可以比較大小的所有資料型別(有比較
C#進階系列——MEF實現設計上的“鬆耦合”(二)
前言:前篇 C#進階系列——MEF實現設計上的“鬆耦合”(一) 介紹了下MEF的基礎用法,讓我們對MEF有了一個抽象的認識。當然MEF的用法可能不限於此,比如MEF的目錄服務、目錄篩選、重組部件等高階應用在這裡就不做過多講解,因為博主覺得這些用法只有在某些特定的環境下面才會用到,著實不太普遍,感覺沒有鑽下去的
C#進階系列——MEF實現設計上的“鬆耦合”(一)
前言:最近去了趟外地出差,介紹推廣小組開發的框架類產品。推廣物件是本部門在專案上面的同事——1到2年工作經驗的初級程式設計師。在給他們介紹框架時發現很多框架設計層面的知識他們都沒有接觸過,甚至沒聽說過,這下囧了~~於是乎在想該如何跟他們解釋MEF、AOP、倉儲模式等方面的東東。本來 C#基礎系列 應該還有兩篇
C#進階系列——MEF實現設計上的“鬆耦合”(四):建構函式注入
前言:今天十一長假的第一天,本因出去走走,奈何博主最大的樂趣是假期坐在電腦前看各處堵車,順便寫寫部落格,有點收穫也是好的。關於MEF的知識,之前已經分享過三篇,為什麼有今天這篇?是因為昨天分享領域服務的時候,用到MEF的注入有參建構函式的方法,博主好奇心重,打算稍微深挖一下,這篇來對此知識點做個總結。 還是
C#進階系列——MEF實現設計上的“鬆耦合”(終結篇:面向介面程式設計)
序:忙碌多事的八月帶著些許的倦意早已步入尾聲,金秋九月承載著抗戰勝利70週年的喜慶撲面而來。沒來得及任何準備,似乎也不需要任何準備,因為生活不需要太多將來時。每天忙著上班、加班、白加班,忘了去憤,忘了去算計所謂的價值。天津爆炸事故時刻警示著我們生命的無常,逝者安息,活著的人生活還得繼續,珍惜生命,遠離傷害。武