DDD領域驅動設計初探(七):Web層的搭建

前言:很久沒更新博客了,天天被該死的業務纏身,今天正好一個模塊完成了,繼續來完善咱們的代碼。以前的六篇完成了領域層、應用層、以及基礎結構層的部分代碼,這篇打算搭建下UI層的代碼。css

DDD領域驅動設計初探系列文章:html

1、UI層介紹

在DDD裏面,UI層的設計也分爲BS和CS,本篇仍是以Web爲例來講明。咱們的Web採用的是MVC+bootstrap的架構。Table組件使用的是bootstrap table,之因此用它是由於它的API比較全,而且博主以爲它的風格適用於各類類型的設備,不管是PC端仍是手機端都都能很好的兼容各類瀏覽器。前端

這裏仍是貼出bootstrap API的相關地址。git

Bootstrap中文網:http://www.bootcss.com/       github

Bootstrap Table Demo:http://issues.wenzhixin.net.cn/bootstrap-table/index.htmlexpress

Bootstrap Table API:http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/編程

Bootstrap Table源碼:https://github.com/wenzhixin/bootstrap-tablebootstrap

Bootstrap DataPicker:http://www.bootcss.com/p/bootstrap-datetimepicker/瀏覽器

Bootstrap離線API架構

2、代碼示例

上篇完成了WCF的設計代碼,可是具體的業務邏輯的代碼尚未,咱們先來實現具體業務的CURD代碼。

一、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接口實現代碼:

  PowerManageWCFService

這裏要說明一點,在經過lamada表達式查詢的方法裏面爲何不直接用Expression<Func<DTO_TB_USERS,bool>>這種類型,而要使用ExpressionNode這種類型的變量呢?

這是由於Expression不支持序列化,沒法用於WCF數據的傳遞。ExpressionNode這個對象的使用須要添加Serialize.Linq這個dll的引用,還好有咱們神奇的NuGet,讓咱們不再用去網上找一大堆的dll了。

咱們公用的增刪改查封裝到了BaseService這個父類裏面。

1.3 BaseService代碼

  BaseService

這個父類主要作了兩件事:一是MEF的初始化;二是通用增刪改查的實現。全部dto對象和領域model的映射都在這裏統一管理。

二、UI層代碼

UI層裏面,爲了更好分離代碼,咱們引入了接口編程的機制,引入了ESTM.Web.IBLL和ESTM.Web.BLL兩個項目,如圖:

爲何要有這麼一個接口層?以前C#進階系列——MEF實現設計上的「鬆耦合」(終結篇:面向接口編程)這篇已經作過介紹,對面向接口編程不瞭解的朋友能夠看看。

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裏面的接口方法

  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裏面的對象。咱們來看代碼:

  PowerManagerController

View頁面

  _Layout.cshtml
  Department.cshtml

JS代碼咱們來看一個頁面就行了,其餘頁面相似:

  DepartmentManage.js

效果圖:

在作頁面數據更新的時候,博主又遇到一個問題:ObjectStateManager 中已存在具備同一鍵的對象。ObjectStateManager 沒法跟蹤具備相同鍵的多個對象。在此仍是記錄下解決方案:

在倉儲的公共實現類中將

     public virtual IQueryable<TEntity> Entities
        {
            get { return UnitOfWork.context.Set<TEntity>(); }
        }

改爲

public virtual IQueryable<TEntity> Entities
        {
            get { return UnitOfWork.context.Set<TEntity>().AsNoTracking() as IQueryable<TEntity>; }
        }

就能夠了。

至此,從領域模型到Web前端的代碼基本完成,可能不少代碼並未完善,好比異常處理、數據驗證等。以前寫過一篇CS版本的權限系統 系統設計——權限系統,不少朋友找我要過源碼,那個時候可能代碼都在工做的項目中,沒辦法抽離出來,在此表示抱歉。如今作了一個BS的,感受BS比CS界面好看,在這裏將源碼分享出來,固然這裏的代碼確定也不太全,不少沒實現的功能還須要本身去實現,可是基本的架子搭起來了,有興趣能夠看看。源碼下載

相關文章
相關標籤/搜索