1. 程式人生 > >asp.net core系列 71 Web架構分層指南

asp.net core系列 71 Web架構分層指南

一.概述

  本章Web架構分層指南,參考了“Microsoft應用程式體系結構指南”(該書是在2009年出版的,當時出版是為了幫助開發人員和架構師更快速,更低風險地使用Microsoft平臺和.NET Framework設計和構建有效,高質量的應用程式)。雖然已過去十年了,技術架構已更新(如流行的DDD/CQRS模式,微服務,容器),但web分層思想還是一樣可取,下面是一個“傳統N分層設計”架構圖,該架構在2010年左右是最流行的,包括了表現層presentation,服務層services,業務層business,資料訪問層data,橫切關注點cross,如下所示:

  

  對比傳統多層或三層.net web架構,下圖是當前流行的.net web微服務架構,在web程式分層之上還包含了容器,web api閘道器,各服務對應的資料儲存(sqlserver,redis,mongoDB),web程式有web api並結合應用了DDD\CQRS分層模式,以及系統各種中介軟體。

  

  下圖是一個訂單微服務站點,包含了簡化的cqrs分層,藍色長方格是表示cqrs分層的職責,包括了查詢 Queries viewModels和命令Command Domain-Model以及上層的應用服務層Application,如下所示

 

  1.1 邏輯分層設計架構型別

    (1) 最傳統的分層是經典三層設計,包括表現層,業務層,資料層.

    (2) 基於服務的解決方案SOA,公開應用程式業務功能的服務層,服務層在業務層之上。

    (3) 基於領域驅動設計的DDD\CQRS分層模式

    (4) 微服務架構。

     這4種web分層架構是不斷的演化改變 ,每一種分層架構並不是獨立的思想,它包含了演化之前的架構分層思想。從以前三層架構到現在的微服務架構,是適應每個時代網際網路業務實現的需求。

功能

SOA

微服務

元件大小

大塊業務邏輯

單獨任務或小塊業務邏輯

耦合

通常鬆耦合

總是鬆耦合

公司架構

任何型別

小型、專注於功能交叉團隊

管理

著重中央管理

著重分散管理

目標

確保應用能夠互動操作

執行新功能、快速拓展開發團隊

 

二.Web分層設計步驟

  1.分層策略
    (1)分層粒度是確定分層策略的關鍵第一步.
    (2)在邏輯分層中, 多層是在同一程序中執行,這可以利用更高效能的通訊機制。例如通過元件介面直接呼叫。必須小心保持層之間的封裝和鬆散耦合。
    (3)在物理分層中,確定合適的通訊機制,該機制考慮到通訊延遲並保持之間的鬆散耦合。
    (4)多層中,考慮它們之間如何相互影響,將確保效能和靈活性之間的良好平衡。

 

  2.確定需要層
    最常用的方法是將表現層,服務層,業務層和資料訪問層功能分離到單獨的層中。某些應用程式還引入了各種元件像快取、日誌、訊息佇列等。

 

  3.決定如何分發各層和元件
    對於web體系架構,一般都是在一個物理層,只有在必要時,才應在不同的物理層上分佈層和元件。這是實現分散式部署的常見原因包括安全策略,物理約束,共享業務邏輯和可伸縮性。

 

  4.確定是否需要摺疊層
    一般規則是您應始終將功能分組到層中。在某些情況下,一個層可以充當代理或傳遞層,提供封裝和鬆散耦合,而不提供大量功能。但是,通過分離該功能,您可以稍後對其進行擴充套件,而對設計中的其他層幾乎沒有影響,如:應用服務層。

 

  5.確定層之間引用的規則
    在分層策略時,您必須定義層如何相互互動的規則(互動是指:各層引用的關係)。指定互動規則的主要原因是最小化依賴性並消除迴圈引用。因此應該遵循以下方法之一:
    (1)自上而下的互動
      較高級別的層可以與下面的層互動,但是較低級別的層不應該與上面的層互動。此規則將幫助您避免層之間的迴圈依賴關係,以及要降低層之間的依賴性。
    (2)嚴格的互動
      每個層必須僅與下面的層進行互動。此規則將強制嚴格分離關注點,其中每個層僅知道下面的層。此規則的好處是對層介面的修改只會影響上面的層。如果您正在設計一個將隨著時間的推移進行修改以引入新功能並且您希望最大限度地減少這些更改的影響的應用程式,或者您正在設計可能分佈在不同物理層上的應用程式,請考慮使用此方法。
    (3)鬆散的互動
      較高級別的層可以繞過層直接與較低級別的層互動。這可以提高效能,但也會增加依賴性。換句話說,對較低級別層的修改可以影響上面的多個層。

    下圖是一個示例:該web架構示例是使用了 cqrs 模式,涉及到了事件源es, 事件源實現本因該分離到命令域和查詢域, 而專案中應用服務層直接引用了底層資料訪問層Dapper(繞過了領域層),  這樣底層Dapper介面方法的修改或換成EF將影響頂層應用服務層,這屬於第三種"鬆散的互動"。 應該推薦使用第一種自上而下的互動。

 

  6.確定跨領域問題
    定義層後,必須標識跨越層的功能。此功能通常被描述為橫切關注點,包括日誌記錄,快取,驗證,身份驗證和異常管理。確定應用程式中的每個橫切關注點非常重要,並設計單獨的元件以儘可能地管理這些問題。此方法可幫助您實現更好的可重用性和可維護性。
    如下圖所示:NLog與Redis是具體實現元件,實現了Common層中的日誌和快取介面,Common層就是橫切元件,是跨層可重用的。像Ioc也是橫切元件。 下圖層的名稱沒有標識跨越層的功能,如果是GFNetCore.Infra.CrossCutting.IoC 這樣命名會更好。

 

  7.定義層之間的介面
    為層定義介面時,主要目標是強制層之間的鬆散耦合。這意味著層不應暴露另一層可能依賴的內部細節。相反,層的介面應設計為通過提供隱藏層內元件細節的公共介面來最小化依賴性。這種隱藏稱為抽象,有許多不同的方法來實現它。以下設計方法可用於定義層的介面:

    (1)抽象介面
      通過定義抽象基類或介面類來實現,該類充當具體類的型別定義。該型別定義了一個公共介面,該層的所有使用者都使用該介面與該層進行互動。這是一種面向介面程式設計,例如:表現層呼叫應用服務層的介面。表現層在CustomerController控制器中如下所示(通過依賴注入後,構造方法來例項):

     //表現層呼叫應用服務層ApplicationService
        private readonly ICustomerAppService _customerAppService;

        public CustomerController(ICustomerAppService customerAppService, 
                                  INotificationHandler<DomainNotification> notifications) : base(notifications)
        {
            _customerAppService = customerAppService;
        }

      但在專案中,為了簡化開發量,表現層呼叫應用服務層的實現類(違反了面向介面程式設計)。表現層在CustomerController控制器中如下所示:

        //呼叫應用服務層ApplicationService
        private readonly CustomerAppService _customerAppService = null;

        //日誌物件
        public readonly ILoggerEX _logger;

        public CustomerController(INotificationHandler<DomainNotification> notifications,
                                  ILoggerEX logger,
                                  CustomerAppService customerAppService)
            : base(notifications)
        {
            _customerAppService = customerAppService;
            _logger = logger;
        }

    (2)依賴倒置

      這是一種程式設計風格,是面向介面程式設計的實現,依賴倒置的應用如:DDD\CQRS, 層依賴於層介面,而不是層依賴於另一個層的實現。依賴注入模式是依賴性反轉的常見實現。依賴性反轉方法提供了靈活性,可以幫助實現可插入設計,因為依賴性是通過配置而不是程式碼組成的。它還可以最大化可測試性,因為您可以輕鬆地將具體測試類注入到設計的不同層中。

      依賴性是通過配置的,如下程式碼所示,由CommandRepository類來實現ICommandRepository介面:

        services.AddScoped<ICommandRepository<CommandModels.Customer>, CommandRepository<CommandModels.Customer>>();
        services.AddScoped<IQueryRepository<QueryModels.Customer>, QueryRepository<QueryModels.Customer>>();

 

    (3) 基於訊息

      可以使用基於訊息的通訊來實現介面並提供層之間的互動,.net技術如:wcf, web services, msmq它們支援跨物理和程序邊界的互動(以xml的soap格式傳輸),但這是對於09年流行的web架構。現在基於訊息多數用web api技術,是面向微服務開發(以json的rest api)。

 

 

 參考資料

   分層應用程式指南