(此文章同時發表在本人微信公眾號“dotNET每日精華文章”,歡迎右邊二維碼來關注。)
題記:ABP框架對多租戶場景提供了很好的支援,內建了多租戶的處理機制,今天我們來深入解析一下這一特性。
最近在基於ABP框架(ASP.NET Boilerplate)開發了一個SaaS。所以接下來可能會時不時分享一下ABP方面的文章。今天來介紹一下ABP對多租戶提供的支援特性。
ABP簡介
ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程式的新起點,它旨在成為一個通用的WEB應用程式框架和專案模板。ASP.NET Boilerplate 基於DDD的經典分層架構思想,實現了眾多DDD的概念(但沒有實現所有DDD的概念)。ABP不僅架構設計和程式碼寫的好,文件也很全面詳實(這是一個開發框架被技術選型的基礎)。尤其國內的很多熱心朋友還整理了中文的資料和文件,比如郭陽銘的系列文章(http://www.cnblogs.com/mienreal/p/4528470.html)和ABP框架中國小組的中文文件(https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese)。
多租戶
通常SaaS都是需要多租戶支援的。維基百科對多租戶的解釋是:軟體多租戶是指一個軟體架構的例項軟體執行在一個伺服器上,但存在多個租戶。租戶是一組共享一個公共的使用者訪問特定許可權的軟體例項。多租戶架構,軟體應用程式旨在提供每個租戶專用的例項包括資料、配置、使用者管理、租戶個體功能和非功能屬性。多租戶與多例項架構,獨立的軟體例項代表不同的租戶操作。
多租戶一般涉及如下幾種場景:
- 多部署-多資料庫:即針對每個租戶獨立部署一套應用程式例項,每個例項對應一個資料庫。這種不算是真正的多租戶,不過對於在設計時沒有考慮多租戶的遺留系統採用這種部署方式不失為一種折中辦法。
- 單部署-多資料庫:只有唯一的一個應用程式例項,每個租戶分別連線不同的資料庫。
- 單部署-單資料庫:應用程式例項和資料庫都是一個。通過在需要隔離資料的資料表中加入一個類似TanantId或EnterpriseId來區分。
- 單部署-混搭資料庫:應用程式例項一個,但是資料庫根據情況,可以是單個或者多個。比如免費使用者放到一個資料庫中,高階使用者分別有自己的資料庫。
- 叢集部署-單/多/混搭資料庫:應用程式的邏輯例項還是一個(只是為了高可用和效能部署為一個叢集),然後對應的資料庫可以是單個、多個和混搭。
另外,除了針對租戶的資料庫以外,可能還需要一個全域性的資料庫(稱之為主機資料庫)來儲存全域性範圍的配置資料。在單資料庫情況下,主機資料可能就和租戶資料放在一起(甚至同一個資料表中)。
ABP對多租戶的支援
上面提到的所有多租戶場景,在ABP都可以支援。只需要在啟動配置中啟用多租戶即可。
Configuration.MultiTenancy.IsEnabled = true;
當然,最常見的場景恐怕就是單部署-單資料庫,所以ABP中內建了處理TenantId的機制(通過介面IMustHaveTenant或IMayHaveTenant來實現)。實體實現了IMustHaveTenant介面,會包含一個不能為空的TenantId屬性,即意味著其中的資料庫需要基於TenantId來進行隔離。實現了IMayHaveTenant介面,會包含一個能為空的TenantId屬性,在TenantId為空的時候代表資料屬於主機範圍的,不為空的時候表示資料基於租戶來隔離。
而ABP通過一個特殊封裝的IAbpSession來給使用者提供當前TenantId的獲取,如果是主機使用者登入系統,那麼TenantId就是為空的,否則就是登入使用者所在租戶的Id。
ABP在多租戶下讀取資料
ABP並非只是簡單的給你的實體類新增一個TenantId屬性,而是通過識別IMustHaveTenant或IMayHaveTenant介面,使用資料過濾機制(根據底層所用ORM不同有不同的實現方式)自動在你讀取資料的時候,基於當前AbpSession中的TenantId來過濾資料。也就是說,你查詢讀取資料的時候,寫“where item.TenantId == AbpSession.TenantId” 這樣的程式碼是毫無必要的。
需要注意的是,如果實體實現的是IMustHaveTenant介面,且AbpSession.TenantId為null的時候(即主機使用者),獲取到的資料是所有租戶的,除非你自己顯式進行過濾。而在IMayHaveTenant情況下,AbpSession.TenantId為null獲取到的是主機使用者的資料。
ABP在多租戶下寫入資料
在多租戶的情形下,寫入資料也通過攔截機制(比如重寫DbContext的SaveChanges方法),可以自動為你的實體設定TenantId屬性,不管你用的是IMustHaveTenant還是IMayHaveTenant。雖然官方文件是推薦在建立實體的時候,總是顯示設定TenantId的,尤其在使用IMayHaveTenant的時候(這也是abp使用者唯一需要關係這個屬性的地方)。但是,就我個人的看法而言,利用框架的原因就是為了讓編碼簡單,所以我還是傾向於建議大家不用顯式設定TenantId。
ABP切換租戶
最後,ABP也提供一系列機制讓你在程式碼中切換tenant(包括租戶與主機間的切換)。關於多租戶的官方文件(http://www.aspnetboilerplate.com/Pages/Documents/Multi-Tenancy)最後的內容也詳細講到了切換租戶的一些最佳實踐。