1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 5061字,需瀏覽 11分鐘

         ·

        2021-01-12 05:34


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

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

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

        當(dāng)在寫 Controller 的時候,你應(yīng)該遵守?單一職責(zé),也就意味著你的 Controller 只需做一件事情,換句話說,只有一個因素或者唯一一個因素能讓你修改 Controller 中的代碼,如果有點(diǎn)懵的話,考慮下面的代碼片段,它將 數(shù)據(jù)訪問代碼 糅進(jìn)了 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ù),這就違反了單一職責(zé)原則,并直接導(dǎo)致了 Controller 的臃腫。

        假如后續(xù)你需要修改?數(shù)據(jù)訪問層?代碼,可能基于更好的性能或者你能想到的原因,這時候只能被迫在 Controller 中修改,舉個例子吧:假如你想把上面的 EF 改成 Dapper 去訪問底層的 Database,更好的做法應(yīng)該是單獨(dú)拎出來一個?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 看起來是不是精簡多了,上面的代碼是不是就是最佳實(shí)踐呢?不完全是,為什么這么說呢?上面這種寫法導(dǎo)致 Controller 變成了?數(shù)據(jù)訪問組件,取出數(shù)據(jù)后必然少不了一些業(yè)務(wù)邏輯處理,這就讓 Controller 違反了?單一職責(zé),對吧,更通用的做法應(yīng)該是將?數(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 實(shí)現(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è)務(wù)邏輯

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

        • 業(yè)務(wù)邏輯

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

        • 驗(yàn)證邏輯

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

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

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

        一旦你用了依賴注入方式,就不需要關(guān)心對象是怎么實(shí)例化的,怎么初始化的,下面的代碼展示了如何在 AuthorController 下的構(gòu)造函數(shù)中實(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 中的重復(fù)代碼

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


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

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

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



        往期精彩回顧




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

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

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

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

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

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

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

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

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

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

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


        瀏覽 23
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            色黄视频在线播放 | 亚洲欧洲小视频 | 乱伦麻豆 | 久久国产视频一区 | 999sesese | 国产一区二区不卡视频 | 熟女人妻久久久一区二区蜜桃老牛 | 国产一级婬片A片免费手机版宅男 | 午夜电影一区 | 黄黄的网站 |