從Microsoft.AspNet.Identity看微軟推薦的一種MVC的分層架構


Microsoft.AspNet.Identity簡介

Microsoft.AspNet.Identity是微軟在MVC 5.0中新引入的一種membership框架,和之前ASP.NET傳統的membership以及WebPage所帶來的SimpleMembership(在MVC 4中使用)都有所不同。

Microsoft.AspNet.Identity是符合微軟開放Owin標准里面Security標准的一種實現。且在MVC 5中默認使用EntityFramework作為Microsoft.AspNet.Identity的數據存儲實現。

從Microsoft.AspNet.Identity里面,我們其實可以看出微軟所采用的一種MVC的分層架構;或許這種分層架構我們可以學習並應用在自己的開發當中。

Microsoft.AspNet.Identity從Preview到RC到RTM一直都有變化,下面我當然以RTM的結構來簡單講解一下這種值得借鑒的參考分層架構。

參考分層架構

首先要說明的是,我上面提到的分層架構不是指MVC本身的分層,而是指Controller與Data之間的分層(與耦合方式)。

你在VS2013中創建一個帶有獨立賬號管理的MVC項目后,默認就有一個用於登錄、注冊的AccountController,通過這個Controller,我們就可以順藤摸瓜一窺Microsoft.AspNet.Identity的真容。

我們先來看一個類圖:

從上圖中,我們可以看到如下類以及他們的關系:

AccountController

賬號管理的Controller。具有一個名為UserManager的屬性,這個屬性的類型為UserManager<TUser>。並暴露一個名為AuthenticationManager的屬性,類型為IAuthenticationManager。

Controller顧名思義只起到控制器的作用,就是把M和V結合在一起,而如何得到M如何處理M得到什么樣的M,就是業務邏輯的事情。

業務邏輯你可以很dirty的寫中Controller里面,也可以像Microsoft.AspNet.Identity一樣把用戶管理的業務邏輯都封裝到UserManager中。

把登錄和注銷邏輯保證到AuthenticationManager中,當然AuthenticationManager實際上是一個來自於Owin的接口IAuthenticationManager,通過這樣的設定,Microsoft.AspNet.Identity就和Owin的Security兼容了。不過我這里不會詳細講Owin的Security的。

AccountController提供了兩個構造方法:

  1. 一個默認的:
     public AccountController()
                : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
            {
            }
  2. 一個可以傳入UserManager實例的:
    public AccountController(UserManager<ApplicationUser> userManager)
            {
                UserManager = userManager;
            }

UserManager<TUser>(Microsoft.AspNet.Identity,Microsoft.AspNet.Identity.Core.dll)

這些一個泛型的用戶管理業務邏輯的類。泛型的原因是因為要支持Profile信息的擴展,這里也不詳細介紹。UserManager<TUser>僅僅是封裝了業務處理的邏輯,並沒有去實現數據如何處理的代碼。相關代碼都交給IUserStore<TUser>。

UserManager<TUser>只提供了一個接受IUserStore<TUser>實例的構造函數:

public UserManager(IUserStore<TUser> store);

IUserStore<TUser>(Microsoft.AspNet.Identity,Microsoft.AspNet.Identity.Core.dll)

這個接口抽象了用戶數據如何處理的邏輯。但是具體實現要交給和具體數據訪問技術相關的實現。從AccountController的默認構造函數中,我們可以看到給UserManager傳入了一個IUserStore<TUser>的實現UserStore<ApplicationUser>。

UserStore<TUser>(Microsoft.AspNet.Identity.EntityFramework,Microsoft.AspNet.Identity.EntityFramework.dll)

這個類實現IUserStore<TUser>接口以及一系列相關接口(比如:IUserLoginStore<TUser>等)。這個類實際上為UserManager提供了對用戶真實數據的訪問能力,在這里,是把用戶數據通過EntityFramework來存儲和獲取的(而數據實際是保存中SQL Server的各類版本中還是保存在MySQL中,就又取決於EntityFramework的數據庫驅動適配層了,和這個分層架構實際上無關了)。而由於UserStore<TUser>是依賴於EntityFramework來存取數據的,所以他的構造函數也接受DbContext作為參數:

public UserStore(DbContext context);

雖然DbContext是一個通用的類,不過從AccountController的構造函數中,我們還是可以看到實際上傳入的是一個繼承於IdentityDbContext<TUser>的DbContext。

IdentityDbContext<TUser>(Microsoft.AspNet.Identity.EntityFramework,Microsoft.AspNet.Identity.EntityFramework.dll)

這是一個包含了Code-First模型定義的DbContext了,其中當然定義了Users這個IDbSet<TUser>,所以對用戶數據的操作最終都是由這個DbContext完成的。

類似架構的講解

這里的這篇文章(http://www.codeproject.com/Articles/207820/The-Repository-Pattern-with-EF-code-first-Dependen)其實就講解了這種類似的分層架構。

其中,文章中提到的IRepository(特定於某個領域類的ICategoryRepository)就是IUserStore,而CategoryRepository就類似於UserStore<TUser>,而CatalogService和UserManager比較接近。

通過依賴注入充分利用這種架構的靈活性

從上面的這些類的構造函數中,我們還可以看到以各種重要特點,就是好幾個類都具有參數構造函數,這樣的設計不得不說是為了依賴注入而准備了。所以,我也簡單講解一下如何用Unity來進行簡單的依賴注入(其他依賴注入框架用法類似)。

首先,通過NuGet來添加Unity和Unity.Mvc這兩個包。

添加以后,在App_Start文件夾里面會出現兩個文件:UnityConfig.cs和UnityMvcActivator.cs,在UnityConfig.cs文件中的RegisterTypes函數中,添加如下兩行代碼:

            container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>();
            container.RegisterType<DbContext, ApplicationDbContext>();

就可以非常簡單地利用Unity來把相關實現類注入進去。所以在這里,你可以把自己實現的UserStore注入進去,假設你的UserStore用到的是類似MongoDB這樣的NoSQL的話,那么你同樣也可以把MongoDB的session注入進去。

通過定義接口,基於接口實現,並在相關類上暴露具有參數的構造函數,可以實現各個分層實現之間的松耦合,並通過依賴注入來極大的增加代碼的靈活性。

總結

在我們的實際項目開發中,如果為了獲得靈活性完全可以照搬這種模式;當然,如果只是想快速實現一個原型或者就是一個小項目的話,那么在Controller里面直接調用DbContext也沒有什么大不了的。

update-2013-11-04 關於ASP.NET Identity的更多信息,可以參考官方文檔:http://www.asp.net/identity/overview/getting-started


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM