• 如何在ASP.NET Core中编写高效的控制器


    ​通过遵循最佳实践,可以编写更好的控制器。所谓的“瘦”控制器(指代码更少、职责更少的控制器)更容易阅读和维护。而且,一旦你的控制器很瘦,可能就不需要对它们进行太多测试了。相反,你可以专注于测试业务逻辑和数据访问代码。瘦控制器的另一个优点是,它更容易维护控制器的多个版本。

    这篇文章讨论了使控制器变胖的坏习惯,然后探索了使控制器变瘦和易于管理的方法。我列出编写控制器的最佳实践可能并不全面,但我已经讨论了最重要的一些,并在适当的情况下提供了相关的源代码。在接下来的几节中,我们将研究什么是胖控制器,为什么它是一种代码坏味道,瘦控制器是什么,为什么它是有益的,以及如何使控制器瘦、简单、可测试和可管理。

    从控制器中删除数据访问代码

    在编写控制器时,你应该坚持单一责任原则,这意味着控制器应该有“一个责任”或“有且只有一个原因可以更改”。换句话说,你希望将更改控制器代码的原因减至最少。下面的代码显示了具有数据访问逻辑的典型控制器。

    在.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

  • 相关阅读:
    odoo开发笔记 -- 后台代码什么时候需要注意编码格式
    mysql添加类似oracle的伪列及查看表信息
    windows10升级系统后,无法远程桌面连接服务器
    时间管理
    odoo开发笔记 -- odoo仪表板集成hightcharts
    odoo开发笔记 -- odoo10 视图界面根据字段状态,动态隐藏创建&编辑按钮
    odoo开发笔记 -- odoo源码下载地址(非官方)
    odoo开发笔记 -- 异常信息处理汇总
    macbook 安装oracle RAC
    ubuntu升级pip后, ImportError: cannot import name ‘main‘
  • 原文地址:https://www.cnblogs.com/hhhnicvscs/p/14414435.html
Copyright © 2020-2023  润新知