<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何在 ASP.NET Core 中寫出更干凈的 Controller

          共 5061字,需瀏覽 11分鐘

           ·

          2021-01-12 05:34


          你可以遵循一些最佳實踐來寫出更干凈的 Controller,一般我們稱這種方法寫出來的 Controller 為瘦Controller,瘦 Controller 的好處在于擁有更少的代碼,更加單一的職責,也便于閱讀和維護,而且隨著時間的推移也容易做 Controller 的多版本。

          這篇文章我們一起討論那些讓 Controler 變胖變臃腫的一些壞味道,并且一起探索讓 Controller 變瘦的手段,雖然我的一些在 Controller 上的最佳實踐可能不是專業(yè)的,但我每一步都提供相關(guān)源代碼來進行優(yōu)化,接下來的章節(jié)中,我們會討論什么是?胖Controller,什么是?壞味道,什么是?瘦Controller,它能帶給我們什么福利?并且如何讓 Controller 變瘦,變簡單,利測試,易維護。

          從 Controller 中移除數(shù)據(jù)層代碼

          當在寫 Controller 的時候,你應該遵守?單一職責,也就意味著你的 Controller 只需做一件事情,換句話說,只有一個因素或者唯一一個因素能讓你修改 Controller 中的代碼,如果有點懵的話,考慮下面的代碼片段,它將 數(shù)據(jù)訪問代碼 糅進了 Controller 。


          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);
          ????}
          ????//Other?action?methods
          }

          請注意上面的代碼在 Action 中使用了 dataContext 從數(shù)據(jù)庫讀取數(shù)據(jù),這就違反了單一職責原則,并直接導致了 Controller 的臃腫。

          假如后續(xù)你需要修改?數(shù)據(jù)訪問層?代碼,可能基于更好的性能或者你能想到的原因,這時候只能被迫在 Controller 中修改,舉個例子吧:假如你想把上面的 EF 改成 Dapper 去訪問底層的 Database,更好的做法應該是單獨拎出來一個?repository?類來操控?數(shù)據(jù)訪問?相關(guān)的代碼,下面是更新后的 AuthorController。


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

          現(xiàn)在 AuthorController 看起來是不是精簡多了,上面的代碼是不是就是最佳實踐呢?不完全是,為什么這么說呢?上面這種寫法導致 Controller 變成了?數(shù)據(jù)訪問組件,取出數(shù)據(jù)后必然少不了一些業(yè)務邏輯處理,這就讓 Controller 違反了?單一職責,對吧,更通用的做法應該是將?數(shù)據(jù)訪問邏輯?封裝在一個 service 層,下面是優(yōu)化之后的 AuthorController 類。


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

          再看一下 AuthorService 類,可以看到它利用了 AuthorRepository ?去做 CURD 操作。


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

          避免寫大量代碼做對象之間映射

          在 DDD 開發(fā)中,經(jīng)常會存在 DTO 和 Domain 對象,在數(shù)據(jù) Input 和 Output 的過程中會存在這兩個對象之間的 mapping,按照普通的寫法大概就是這樣的。


          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;
          ????//Other?code
          ???......
          }

          可以看到,這種一一映射的寫法讓 Controller 即時膨脹,同時也讓 Controller 增加了額外的功能,那如何把這種?模板式?代碼規(guī)避掉呢?可以使用專業(yè)的?對象映射框架 AutoMapper?去解決,下面的代碼展示了如何做 ?AutoMapper 的配置。


          public?class?AutoMapping
          {
          ????public?static?void?Initialize()
          ????{
          ????????Mapper.Initialize(cfg?=>
          ????????{
          ????????????cfg.CreateMap();
          ????????????//Other?code????????????
          ????????});
          ????}
          }

          接下來可以在?Global.asax?中調(diào)用?Initialize()?初始化,如下代碼所示:


          protected?void?Application_Start()
          {
          ????AutoMapping.Initialize();?????????
          }

          最后,可以將 mapping 邏輯放在 service 層中,請注意下面的代碼是如何使用 AutoMapper 實現(xiàn)兩個不兼容對象之間的映射。


          public?class?AuthorService
          {
          ????private?AuthorRepository?authorRepository?=?new?AuthorRepository();
          ????public?AuthorDTO?GetAuthor?(int?authorId)
          ????{
          ????????var?author?=?authorRepository.GetAuthor(authorId);
          ????????return?Mapper.Map(author);
          ????}
          ????//Other?methods
          }

          避免在 Controller 中寫業(yè)務邏輯

          盡量避免在 Controller 中寫?業(yè)務邏輯?或者?驗證邏輯, Controller 中應該僅僅是接收一個請求,然后被下一個 action 執(zhí)行,別無其它,回到剛才的問題,這兩種邏輯該怎么處理呢?

          • 業(yè)務邏輯

          這些邏輯可以封裝 XXXService 類中,比如之前創(chuàng)建的 AuthorService。

          • 驗證邏輯

          這些邏輯可以用 AOP 的操作手法,比如將其塞入到 Request Pipeline 中處理。

          使用依賴注入而不是硬組合

          推薦在 Controller 中使用依賴注入的方式來實現(xiàn)對象之間的管理,依賴注入是 控制反轉(zhuǎn) 的一個子集,它通過外部注入對象之間的依賴從而解決內(nèi)部對象之間的依賴,很拗口是吧!

          一旦你用了依賴注入方式,就不需要關(guān)心對象是怎么實例化的,怎么初始化的,下面的代碼展示了如何在 AuthorController 下的構(gòu)造函數(shù)中實現(xiàn) IAuthorService 對象的注入。


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

          使用 action filer 消除 Controller 中的重復代碼

          可以利用 action filter 在 Request pipeline 這個管道的某些點上安插一些你的自定義代碼,舉個例子,可以使用 ActionFilter 在 Action 的執(zhí)行前后安插一些自定義代碼,而不是將這些業(yè)務邏輯放到 Controller 中,讓 Controller 不必要的膨脹,下面的代碼展示了如何去實現(xiàn)。


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

          總的來說,如果一個 Controller 被賦予了幾個職責,那么只要是其中任何一個職責的原因,你都必須對 Controller 進行修改,總的來說,一定要堅守?單一原則

          譯文鏈接:https://www.infoworld.com/article/3404472/how-to-write-efficient-controllers-in-aspnet-core.html



          往期精彩回顧




          【推薦】.NET Core開發(fā)實戰(zhàn)視頻課程?★★★

          .NET Core實戰(zhàn)項目之CMS 第一章 入門篇-開篇及總體規(guī)劃

          【.NET Core微服務實戰(zhàn)-統(tǒng)一身份認證】開篇及目錄索引

          Redis基本使用及百億數(shù)據(jù)量中的使用技巧分享(附視頻地址及觀看指南)

          .NET Core中的一個接口多種實現(xiàn)的依賴注入與動態(tài)選擇看這篇就夠了

          10個小技巧助您寫出高性能的ASP.NET Core代碼

          用abp vNext快速開發(fā)Quartz.NET定時任務管理界面

          在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務輕松實現(xiàn)作業(yè)調(diào)度

          現(xiàn)身說法:實際業(yè)務出發(fā)分析百億數(shù)據(jù)量下的多表查詢優(yōu)化

          關(guān)于C#異步編程你應該了解的幾點建議

          C#異步編程看這篇就夠了


          瀏覽 23
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美色图久久 | 亚洲成人在线视频导航 | 五月丁香乱伦文学 | 伊人国产综合视频在线 | 国产在线不卡 |