如何在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
如何在ASP.NET Core中编写高效的控制器的更多相关文章
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
- 如何在 ASP.Net Core 中使用 Lamar
ASP.Net Core 自带了一个极简的 开箱即用 的依赖注入容器,实际上,你还可以使用第三方的 依赖注入容器 来替代它,依赖注入是一种设计模式,它能够有效的实现对象之间的解耦并有利于提高单元测试和 ...
- 如何在ASP.NET Core中实现CORS跨域
注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...
- 如何在ASP.NET Core中实现一个基础的身份认证
注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...
- 如何在ASP.NET Core中应用Entity Framework
注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...
- [转]如何在ASP.NET Core中实现一个基础的身份认证
本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...
- 如何在ASP.NET Core中使用Azure Service Bus Queue
原文:USING AZURE SERVICE BUS QUEUES WITH ASP.NET CORE SERVICES 作者:damienbod 译文:如何在ASP.NET Core中使用Azure ...
- 如何在ASP.NET Core中使用JSON Patch
原文: JSON Patch With ASP.NET Core 作者:.NET Core Tutorials 译文:如何在ASP.NET Core中使用JSON Patch 地址:https://w ...
- [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置
[翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...
随机推荐
- 为什么在使用LESS 除法计算时会出问题
hello,各位小伙伴们好,最近一直有小伙伴问我为什么写Less的时候,发现除法有了问题,在生成的css文件中,不给我们输出正确结果了. 直接抛结论: LESS 版本升级,EasyLess插件 新版本 ...
- 获取本机IP和主机名
如果是在windows环境: 使用InetAddress.getLocalHost()方法即可 package com.datongsoft.wg.common.util; import java.n ...
- Spring MVC参数处理
使用Servlet API作为参数 HttpServletRequest HttpServletResponse HttpSession 使用流作为参数 总结 Spring MVC通过分析处理处理方法 ...
- 带撤销并查集 & 可持久化并查集
带撤销并查集支持从某个元素从原来的集合中撤出来,然后加入到一个另外一个集合中,或者删除该元素 用一个映射来表示元素和并查集中序号的关系,代码中用\(to[x]\) 表示x号元素在并查集中的 id 删除 ...
- 【洛谷 p3376】模板-网络最大流(图论)
题目:给出一个网络图,以及其源点和汇点,求出其网络最大流. 解法:网络流Dinic算法. 1 #include<cstdio> 2 #include<cstdlib> 3 #i ...
- java大数函数(附官方文档链接)
java文档 字段摘要 static BigInteger ONE BigInteger 的常量 1. static BigInteger TEN BigInt ...
- 【noi 2.6_9277】Logs Stacking堆木头(DP)
题意:给出在最底层的木头的个数,问有多少种堆放木头的方式.要求木头必须互相挨着在一起. 解法:f[i]表示最底层i个木头的堆放木头的方式.注意递推的思想!只需知道上一层堆放0~i-1个(即最底层堆放i ...
- Educational Codeforces Round 94 (Rated for Div. 2) String Similarity、RPG Protagonist、Binary String Reconstruction、Zigzags 思维
题目链接:String Similarity 题意: 首先题目定义了两个串的相似(串的构成是0.1),如果两个串存在对于一个下标k,它们的值一样,那么这两个串就相似 然后题目给你一个长度为2n-1的串 ...
- JavaScript——原型
原型中的原先设定的值不能改变!!!
- C# 类 (11) - Const
Const variable 变量 ,值可变的constant 常量,不可变,C# 里关键字是const当我们定义一个常量的时候,需要立马赋值,以后不能再改这个量了我们可以把常量定义在 method ...