通过遵循最佳实际,能够编写更好的控制器。所谓的“瘦”控制器(指代码更少、职责更少的控制器)更容易浏览和保护。而且,一旦你的控制器很瘦,可能就不须要对它们进行太多测试了。相同,你能够专一于测试业务逻辑和数据拜访代码。瘦控制器的另一个长处是,它更容易保护控制器的多个版本。
这篇文章探讨了使控制器变胖的坏习惯,而后摸索了使控制器变瘦和易于治理的办法。我列出编写控制器的最佳实际可能并不全面,但我曾经探讨了最重要的一些,并在适当的状况下提供了相干的源代码。在接下来的几节中,咱们将钻研什么是胖控制器,为什么它是一种代码坏滋味,瘦控制器是什么,为什么它是无益的,以及如何使控制器瘦、简略、可测试和可治理。
从控制器中删除数据拜访代码
在编写控制器时,你应该保持繁多责任准则,这意味着控制器应该有“一个责任”或“有且只有一个起因能够更改”。换句话说,你心愿将更改控制器代码的起因减至起码。上面的代码显示了具备数据拜访逻辑的典型控制器。
在.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/art…
欢送关注我的公众号,如果你有喜爱的外文技术文章,能够通过公众号留言举荐给我。