0.引言
該系列博文主要在【官方文檔】及【tkbSimplest】ABP框架理論研究系列博文的基礎上進行總結的,或許大家會質問,別人都已經翻譯過了,這不是多此一舉嗎?原因如下:
1.【tkbSimplest】的相關博文由於撰寫得比較早的,在參照官方文檔學習的過程中,發現部分知識未能及時同步(當前V4.0.2版本),如【EntityHistory】、【Multi-Lingual Engities】章節未涉及、【Caching】章節沒有Entity Caching等內容。
2.進一步深入學習ABP的理論知識。
3.借此機會提高英文文檔的閱讀能力,故根據官方當前最新的版本,並在前人的基礎上,自己也感受一下英文幫助文檔的魅力。
好了,下面開始進入正題。
1.APB是什么?
ABP是ASP.NET Boilerplate的簡稱,從英文字面上理解它是一個關於ASP.NET的模板,在github上已經有5.7k的star(截止2018年11月21日)。官方的解釋:ABP是一個開源且文檔友好的應用程序框架。ABP不僅僅是一個框架,它還提供了一個最徍實踐的基於領域驅動設計(DDD)的體系結構模型。
ABP與最新的ASP.NET CORE和EF CORE版本保持同步,同樣也支持ASP.NET MVC 5.x和EF6.x。
2.一個快速事例
讓我們研究一個簡單的類,看看ABP具有哪些優點:
這里我們看到一個Application Service(應用服務)方法。在DDD中,應用服務直接用於表現層(UI)執行應用程序的用例。那么在UI層中就可以通過javascript ajax的方式調用UpdateTask方法。
3.ABP的優點
通過上述事例,讓我們來看看ABP的一些優點:
依賴注入(Dependency Injection):ABP使用並提供了傳統的DI基礎設施。上述TaskAppService類是一個應用服務(繼承自ApplicationService),所以它按照慣例以短暫(每次請求創建一次)的形式自動注冊到DI容器中。同樣的,也可以簡單地注入其他依賴(如事例中的IRepository<Task>)。
部分源碼分析:TaskAppService類繼承自ApplicationService,IApplicaitonServcie又繼承自ITransientDependency接口,在ABP框架中已經將ITransientDependency接口注入到DI容器中,所有繼承自ITransientDependency接口的類或接口都會默認注入。
倉儲(Repository):ABP可以為每一個實體創建一個默認的倉儲(如事例中的IRepository<Task>)。默認的倉儲提供了很多有用的方法,如事例中的FirstOrDefault方法。當然,也可以根據需求擴展默認的倉儲。倉儲抽象了DBMS和ORMs,並簡化了數據訪問邏輯。
授權(Authorization):ABP可以通過聲明的方式檢查權限。如果當前用戶沒有【update task】的權限或沒有登錄,則會阻止訪問UpdateTask方法。ABP不僅提供了聲明屬性的方式授權,而且還可以通過其它的方式。
部分源碼分析:AbpAuthorizeAttribute類實現了Attribute,可在類或方法上通過【AbpAuthorize】聲明。
通過AuthorizationProvider類中的SetPermissions方法進行自定義授權。
驗證(Validation):ABP自動檢查輸入是否為null。它也基於標准數據注釋特性和自定義驗證規則驗證所有的輸入屬性。如果請求無效,它會在客戶端拋出適合的驗證異常。
部分源碼分析:ABP框架中主要通過攔截器ValidationInterceptor(AOP實現方式之一,)實現驗證,該攔截器在ValidationInterceptorRegistrar的Initialize方法中調用。
自定義Customvalidator類
審計日志(Audit Logging):基於約定和配置,用戶、瀏覽器、IP地址、調用服務、方法、參數、調用時間、執行時長以及其它信息會為每一個請求自動保存。
部分源碼分析:ABP框架中主要通過攔截器AuditingInterceptor(AOP實現方式之一,)實現審計日志,該攔截器在AuditingInterceptorRegistrar的Initialize方法中調用。
工作單元(Unit Of Work):在ABP中,應用服務方法默認視為一個工作單元。它會自動創建一個連接並在方法的開始位置開啟事務。如果方法成功完成並沒有異常,事務會提交並釋放連接。即使這個方法使用不同的倉儲或方法,它們都是原子的(事務的)。當事務提交時,實體的所有改變都會自動保存。如上述事例所示,甚至不需要調用_repository.Update(task)方法。
部分源碼分析:ABP框架中主要通過攔截器UnitOfWorkInterceptor(AOP實現方式之一,)實現工作單元,該攔截器在UnitOfWorkRegistrar的Initialize方法中調用。
異常處理(Exception):在使用了ABP框架的Web應用程序中,我們幾乎不用手動處理異常。默認情況下,所有的異常都會自動處理。如果發生異常,ABP會自動記錄並給客戶端返回合適的結果。例如:對於一個ajax請求,返回一個json對象給客戶端,表明發生了錯誤。但會對客戶端隱藏實際的異常,除非像上述事例那樣使用UserFriendlyException方法拋出。它也理解和處理客戶端的錯誤,並向客戶端顯示合適的信息。
部分源碼分析:UserFriendlyException拋出異常方法。
日志(Logging):由上述事例可見,可以通過在基類定義的Logger對象來寫日志。ABP默認使用了Log4Net,但它是可更改和可配置的。
部分源碼分析:Log4NetLoggerFactory類。
本地化(Localization):注意,在上述事例中使用了L("XXX")方法處理拋出的異常。因此,它會基於當前用戶的文化自動實現本地化。詳細見后續本地化章節。
部分源碼分析:......
自動映射(Auto Mapping):在上述事例最后一行代碼,使用了ABP的MapTo擴展方法將輸入對象的屬性映射到實體屬性。ABP使用AutoMapper第三方庫執行映射。根據命名慣例可以很容易的將屬性從一個對象映射到另一個對象。
部分源碼分析:AutoMapExtensions類中的MapTo()方法。
動態API層(Dynamic API Layer):在上述事例中,TaskAppService實際上是一個簡單的類。通常必須編寫一個Web API Controller包裝器給js客戶端暴露方法,而ABP會在運行時自動完成。通過這種方式,可以在客戶端直接使用應用服務方法。
部分源碼分析:......
動態javascript ajax代理(Dynamic JavaScript AJAX Proxy):ABP創建動態代理方法,從而使得調用應用服務方法就像調用客戶端的js方法一樣簡單。
部分源碼分析:......
4.本章小節
通過上述簡單的類可以看到ABP的優點。完成所有這些任務通常需要花費大量的時間,但是ABP框架會自動處理。
除了這個上述簡單的事例外,ABP還提供了一個健壯的基礎設施和開發模型,如模塊化、多租戶、緩存、后台工作、數據過濾、設置管理、領域事件、單元&集成測試等等,那么你可以專注於業務代碼,而不需要重復做這些工作(DRY)。