asp.net core系列 71 Web架构分层指南
一.概述
本章Web架構(gòu)分層指南,參考了“Microsoft應(yīng)用程序體系結(jié)構(gòu)指南”(該書是在2009年出版的,當(dāng)時出版是為了幫助開發(fā)人員和架構(gòu)師更快速,更低風(fēng)險地使用Microsoft平臺和.NET Framework設(shè)計和構(gòu)建有效,高質(zhì)量的應(yīng)用程序)。雖然已過去十年了,技術(shù)架構(gòu)已更新(如流行的DDD/CQRS模式,微服務(wù),容器),但web分層思想還是一樣可取,下面是一個“傳統(tǒng)N分層設(shè)計”架構(gòu)圖,該架構(gòu)在2010年左右是最流行的,包括了表現(xiàn)層presentation,服務(wù)層services,業(yè)務(wù)層business,數(shù)據(jù)訪問層data,橫切關(guān)注點cross,如下所示:
對比傳統(tǒng)多層或三層.net web架構(gòu),下圖是當(dāng)前流行的.net web微服務(wù)架構(gòu),在web程序分層之上還包含了容器,web api網(wǎng)關(guān),各服務(wù)對應(yīng)的數(shù)據(jù)存儲(sqlserver,redis,mongoDB),web程序有web api并結(jié)合應(yīng)用了DDD\CQRS分層模式,以及系統(tǒng)各種中間件。
下圖是一個訂單微服務(wù)站點,包含了簡化的cqrs分層,藍色長方格是表示cqrs分層的職責(zé),包括了查詢 Queries viewModels和命令Command Domain-Model以及上層的應(yīng)用服務(wù)層Application,如下所示
1.1?邏輯分層設(shè)計架構(gòu)類型
(1)?最傳統(tǒng)的分層是經(jīng)典三層設(shè)計,包括表現(xiàn)層,業(yè)務(wù)層,數(shù)據(jù)層.
(2)?基于服務(wù)的解決方案SOA,公開應(yīng)用程序業(yè)務(wù)功能的服務(wù)層,服務(wù)層在業(yè)務(wù)層之上。
(3)?基于領(lǐng)域驅(qū)動設(shè)計的DDD\CQRS分層模式
(4)?微服務(wù)架構(gòu)。
? 這4種web分層架構(gòu)是不斷的演化改變 ,每一種分層架構(gòu)并不是獨立的思想,它包含了演化之前的架構(gòu)分層思想。從以前三層架構(gòu)到現(xiàn)在的微服務(wù)架構(gòu),是適應(yīng)每個時代互聯(lián)網(wǎng)業(yè)務(wù)實現(xiàn)的需求。
功能 | SOA | 微服務(wù) |
組件大小 | 大塊業(yè)務(wù)邏輯 | 單獨任務(wù)或小塊業(yè)務(wù)邏輯 |
耦合 | 通常松耦合 | 總是松耦合 |
公司架構(gòu) | 任何類型 | 小型、專注于功能交叉團隊 |
管理 | 著重中央管理 | 著重分散管理 |
目標 | 確保應(yīng)用能夠交互操作 | 執(zhí)行新功能、快速拓展開發(fā)團隊 |
二.Web分層設(shè)計步驟
1.分層策略
(1)分層粒度是確定分層策略的關(guān)鍵第一步.
(2)在邏輯分層中, 多層是在同一進程中運行,這可以利用更高性能的通信機制。例如通過組件接口直接調(diào)用。必須小心保持層之間的封裝和松散耦合。
(3)在物理分層中,確定合適的通信機制,該機制考慮到通信延遲并保持之間的松散耦合。
(4)多層中,考慮它們之間如何相互影響,將確保性能和靈活性之間的良好平衡。
2.確定需要層
最常用的方法是將表現(xiàn)層,服務(wù)層,業(yè)務(wù)層和數(shù)據(jù)訪問層功能分離到單獨的層中。某些應(yīng)用程序還引入了各種組件像緩存、日志、消息隊列等。
3.決定如何分發(fā)各層和組件
對于web體系架構(gòu),一般都是在一個物理層,只有在必要時,才應(yīng)在不同的物理層上分布層和組件。這是實現(xiàn)分布式部署的常見原因包括安全策略,物理約束,共享業(yè)務(wù)邏輯和可伸縮性。
4.確定是否需要折疊層
一般規(guī)則是您應(yīng)始終將功能分組到層中。在某些情況下,一個層可以充當(dāng)代理或傳遞層,提供封裝和松散耦合,而不提供大量功能。但是,通過分離該功能,您可以稍后對其進行擴展,而對設(shè)計中的其他層幾乎沒有影響,如:應(yīng)用服務(wù)層。
5.確定層之間引用的規(guī)則
在分層策略時,您必須定義層如何相互交互的規(guī)則(交互是指:各層引用的關(guān)系)。指定交互規(guī)則的主要原因是最小化依賴性并消除循環(huán)引用。因此應(yīng)該遵循以下方法之一:
(1)自上而下的交互
較高級別的層可以與下面的層交互,但是較低級別的層不應(yīng)該與上面的層交互。此規(guī)則將幫助您避免層之間的循環(huán)依賴關(guān)系,以及要降低層之間的依賴性。
(2)嚴格的互動
每個層必須僅與下面的層進行交互。此規(guī)則將強制嚴格分離關(guān)注點,其中每個層僅知道下面的層。此規(guī)則的好處是對層界面的修改只會影響上面的層。如果您正在設(shè)計一個將隨著時間的推移進行修改以引入新功能并且您希望最大限度地減少這些更改的影響的應(yīng)用程序,或者您正在設(shè)計可能分布在不同物理層上的應(yīng)用程序,請考慮使用此方法。
(3)松散的互動
較高級別的層可以繞過層直接與較低級別的層交互。這可以提高性能,但也會增加依賴性。換句話說,對較低級別層的修改可以影響上面的多個層。
下圖是一個示例:該web架構(gòu)示例是使用了 cqrs 模式,涉及到了事件源es, 事件源實現(xiàn)本因該分離到命令域和查詢域, 而項目中應(yīng)用服務(wù)層直接引用了底層數(shù)據(jù)訪問層Dapper(繞過了領(lǐng)域?qū)?, ?這樣底層Dapper接口方法的修改或換成EF將影響頂層應(yīng)用服務(wù)層,這屬于第三種"松散的互動"。?應(yīng)該推薦使用第一種自上而下的交互。
6.確定跨領(lǐng)域問題
定義層后,必須標識跨越層的功能。此功能通常被描述為橫切關(guān)注點,包括日志記錄,緩存,驗證,身份驗證和異常管理。確定應(yīng)用程序中的每個橫切關(guān)注點非常重要,并設(shè)計單獨的組件以盡可能地管理這些問題。此方法可幫助您實現(xiàn)更好的可重用性和可維護性。
如下圖所示:NLog與Redis是具體實現(xiàn)組件,實現(xiàn)了Common層中的日志和緩存接口,Common層就是橫切組件,是跨層可重用的。像Ioc也是橫切組件。下圖層的名稱沒有標識跨越層的功能,如果是GFNetCore.Infra.CrossCutting.IoC 這樣命名會更好。
7.定義層之間的接口
為層定義接口時,主要目標是強制層之間的松散耦合。這意味著層不應(yīng)暴露另一層可能依賴的內(nèi)部細節(jié)。相反,層的接口應(yīng)設(shè)計為通過提供隱藏層內(nèi)組件細節(jié)的公共接口來最小化依賴性。這種隱藏稱為抽象,有許多不同的方法來實現(xiàn)它。以下設(shè)計方法可用于定義層的接口:
(1)抽象接口
通過定義抽象基類或接口類來實現(xiàn),該類充當(dāng)具體類的類型定義。該類型定義了一個公共接口,該層的所有使用者都使用該接口與該層進行交互。這是一種面向接口編程,例如:表現(xiàn)層調(diào)用應(yīng)用服務(wù)層的接口。表現(xiàn)層在CustomerController控制器中如下所示(通過依賴注入后,構(gòu)造方法來實例):
private readonly ICustomerAppService _customerAppService;
public CustomerController(ICustomerAppService customerAppService,
INotificationHandler<DomainNotification> notifications) : base(notifications)
{
_customerAppService = customerAppService;
}
但在項目中,為了簡化開發(fā)量,表現(xiàn)層調(diào)用應(yīng)用服務(wù)層的實現(xiàn)類(違反了面向接口編程)。表現(xiàn)層在CustomerController控制器中如下所示:
//調(diào)用應(yīng)用服務(wù)層ApplicationServiceprivate readonly CustomerAppService _customerAppService = null;
//日志對象
public readonly ILoggerEX _logger;
public CustomerController(INotificationHandler<DomainNotification> notifications,
ILoggerEX logger,
CustomerAppService customerAppService)
: base(notifications)
{
_customerAppService = customerAppService;
_logger = logger;
}
(2)依賴倒置
這是一種編程風(fēng)格,是面向接口編程的實現(xiàn),依賴倒置的應(yīng)用如:DDD\CQRS, 層依賴于層接口,而不是層依賴于另一個層的實現(xiàn)。依賴注入模式是依賴性反轉(zhuǎn)的常見實現(xiàn)。依賴性反轉(zhuǎn)方法提供了靈活性,可以幫助實現(xiàn)可插入設(shè)計,因為依賴性是通過配置而不是代碼組成的。它還可以最大化可測試性,因為您可以輕松地將具體測試類注入到設(shè)計的不同層中。
依賴性是通過配置的,如下代碼所示,由CommandRepository類來實現(xiàn)ICommandRepository接口:
services.AddScoped<ICommandRepository<CommandModels.Customer>, CommandRepository<CommandModels.Customer>>();services.AddScoped<IQueryRepository<QueryModels.Customer>, QueryRepository<QueryModels.Customer>>();
(3) 基于消息
可以使用基于消息的通信來實現(xiàn)接口并提供層之間的交互,.net技術(shù)如:wcf, web services, msmq它們支持跨物理和進程邊界的交互(以xml的soap格式傳輸),但這是對于09年流行的web架構(gòu)。現(xiàn)在基于消息多數(shù)用web api技術(shù),是面向微服務(wù)開發(fā)(以json的rest api)。
參考資料
分層應(yīng)用程序指南
原文鏈接:https://www.cnblogs.com/MrHSR/p/11272400.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?
總結(jié)
以上是生活随笔為你收集整理的asp.net core系列 71 Web架构分层指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019 年 8 月编程语言排行榜,C#
- 下一篇: 谈自由,ASP.NET Core才是未来