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

碼農譯站發表於2021-02-19

​通過遵循最佳實踐,可以編寫更好的控制器。所謂的“瘦”控制器(指程式碼更少、職責更少的控制器)更容易閱讀和維護。而且,一旦你的控制器很瘦,可能就不需要對它們進行太多測試了。相反,你可以專注於測試業務邏輯和資料訪問程式碼。瘦控制器的另一個優點是,它更容易維護控制器的多個版本。

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

從控制器中刪除資料訪問程式碼

在編寫控制器時,你應該堅持單一責任原則,這意味著控制器應該有“一個責任”或“有且只有一個原因可以更改”。換句話說,你希望將更改控制器程式碼的原因減至最少。下面的程式碼顯示了具有資料訪問邏輯的典型控制器。

在.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操作。

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

避免編寫樣板程式碼來對映物件

你經常需要對映資料傳輸物件(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是如何被用來對映兩個不相容的型別Author和AuthorDTO的。

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");
}

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

原文連結:https://www.infoworld.com/article/3404472/how-to-write-efficient-controllers-in-aspnet-core.html

相關文章