如何在ASP.NET Core中編寫高效的控制器

經過遵循最佳實踐,能夠編寫更好的控制器。所謂的「瘦」控制器(指代碼更少、職責更少的控制器)更容易閱讀和維護。並且,一旦你的控制器很瘦,可能就不須要對它們進行太多測試了。相反,你能夠專一於測試業務邏輯和數據訪問代碼。瘦控制器的另外一個優勢是,它更容易維護控制器的多個版本。數據庫

這篇文章討論了使控制器變胖的壞習慣,而後探索了使控制變瘦和易於管理的方法。我列出編寫控制器的最佳實踐可能並不全面,但我已經討論了最重要的一些,並在適當的狀況下提供了相關的源代碼。在接下來的幾節中,咱們將研究什麼是胖控制器,爲何它是一種代碼壞味道,瘦控制器是什麼,爲何它是有益的,以及如何使控制器瘦、簡單、可測試和可管理。微信

從控制器中刪除數據訪問代碼app

在編寫控制器時,你應該堅持單一責任原則,這意味着控制器應該有「一個責任」或「有且只有一個緣由能夠更改」。換句話說,你但願將更改控制器代碼的緣由減至最少。下面的代碼顯示了具備數據訪問邏輯的典型控制器。asp.net

在.NET生態系統中使用特定的技術堆棧會產生一些困惑,由於有不少選擇,好比應該使用哪一種類型的運行時?在這篇文章中,咱們將試圖把這些要點都說清楚。函數

public class AuthorController : Controller{    private AuthorContext dataContext = new AuthorContext();    public ActionResult Index(int authorId)    {        var authors = dataContext.Authors            .OrderByDescending(x=>x.JoiningDate)            .Where(x=>x.AuthorId == authorId)            .ToList();        return View(authors);    }}

在action內部使用數據上下文實例讀取數據,違反了單一職責原則,並使你的控制器充斥着不該該出如今那裏的代碼。在本例中,咱們使用一個DataContext(假設咱們使用Entity Framework Core)來鏈接、處理數據庫中的數據。工具

明天若是你決定更改數據訪問技術(爲了更好的性能或其餘緣由),你也必須更改你的控制器。例如,若是我想使用Dapper鏈接到底層數據庫該怎麼辦?更好的方法是使用repository類來封裝數據訪問邏輯(儘管我不太喜歡repository模式)。讓咱們用如下代碼更新AuthorController。性能

public class AuthorController : Controller{    private AuthorRepository authorRepository = new AuthorRepository();    public ActionResult Index(int authorId)    {        var authors = authorRepository.GetAuthor(authorId);        return View(authors);    }}

控制器如今看起來更瘦了。那麼這是編寫這個控制器的最佳方法嗎?不是。若是你的控制器正在訪問數據訪問組件,那麼它將作太多的事情,所以違反了單一職責原則。控制器不該該有直接訪問數據訪問組件的數據訪問邏輯或代碼。下面是AuthorController類的改進版本。測試

public class AuthorController : Controller{    private AuthorService authorService = new AuthorService();    public ActionResult Index(int authorId)    {        var authors = authorService.GetAuthor(authorId);        return View(authors);    }}

AuthorService類利用AuthorRepository類執行CRUD操做。this

public class AuthorService{    private AuthorRepository authorRepository = new AuthorRepository();    public Author GetAuthor (int authorId)    {        return authorRepository.GetAuthor(authorId);    }}

避免編寫樣板代碼來映射對象spa

你常常須要映射數據傳輸對象(DTO)和域對象,反之亦然。請參考下面給出的代碼片斷,它顯示了控制器方法內部的映射邏輯。

public IActionResult GetAuthor(int authorId){    var author = authorService.GetAuthor(authorId);    var authorDTO = new AuthorDTO();    authorDTO.AuthorId = author.AuthorId;    authorDTO.FirstName = author.FirstName;    authorDTO.LastName = author.LastName;    authorDTO.JoiningDate = author.JoiningDate; }

你不該該在控制器中編寫這樣的映射邏輯,由於它會使控制器膨脹並增長額外的責任。若是你要編寫映射邏輯,能夠利用像AutoMapper這樣的對象映射器工具來避免編寫大量樣板代碼。

最後,你應該將映射邏輯移到前面建立的服務類中。注意AutoMapper是如何被用來映射兩個不兼容的類型AuthorAuthorDTO的。

public class AuthorService{    private AuthorRepository authorRepository = new AuthorRepository();    public AuthorDTO GetAuthor (int authorId)    {        var author = authorRepository.GetAuthor(authorId);        return Mapper.Map<AuthorDTO>(author);    }}

避免在控制器中編寫業務邏輯代碼

不該該在控制器中編寫業務邏輯或驗證邏輯。控制器應該只接受一個請求,而後跳轉下一個action,除此以外沒有其餘的。全部的業務邏輯代碼都應該轉移到其餘類中(好比咱們前面建立的AuthorService類)。有幾種方法能夠在請求管道中設置驗證器,而不要在控制器中編寫驗證邏輯。這會使你的控制器變得沒必要要的臃腫,並讓它負責它不該該作的任務。

更喜歡依賴注入而不是組合

你應該更喜歡在控制器中使用依賴項注入來管理依賴項。依賴注入是控制反轉(IoC)原則的一個子集。它用於經過容許從外部注入的依賴項刪除內部依賴項。

經過利用依賴注入,你沒必要關心對象的實例化、初始化等。你能夠有一個返回所需類型實例的工廠,而後可使用構造函數注入來使用該實例。下面的代碼片斷說明了如何使用構造函數將IAuthorService類型的實例注入到AuthorController。(假設IAuthorService是AuthorService類擴展的接口。)

public class AuthorController : Controller{    private IAuthorService authorService = new AuthorService();    public AuthorController(IAuthorService authorService)    {       this.authorService = authorService;    }}

使用action過濾器來消除重複的代碼

能夠在asp.net core中使用action過濾器在請求管道中的特定點執行定製代碼。例如,你可使用action過濾器在操做action方法執行以前和以後執行自定義代碼。你能夠從控制器的action方法中刪除驗證邏輯,並將其寫入action過濾器中,而不是在控制器中編寫驗證邏輯。下面的代碼片斷顯示瞭如何實現這一點。

[ValidateModelState][HttpPost]public ActionResult Create(AuthorRequest request){    AuthorService authorService = new AuthorService();    authorService.Save(request);    return RedirectToAction("Home");}

你將多個職責分配給了一個控制器,那麼也會有多個緣由致使控制器更改。所以,這違反了單一責任原則,該原則規定類應該有且只有一個變動的理由。

 

 

 

本文分享自微信公衆號 - 碼農譯站(gh_c0d62fbb4bda)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索