使用依赖关系注入在ASP.NET Core中编写干净代码
作者:网络转载 发布时间:[ 2016/5/23 13:24:10 ] 推荐标签:测试开发技术 .NET
图 2 域模型中的业务逻辑
public RsvpResult AddRsvp(string name, string email, DateTime currentDateTime)
{
if (currentDateTime > RsvpDeadlineDateTime())
{
return new RsvpResult("Failed - Past deadline.");
}
var rsvp = new Rsvp()
{
DateCreated = currentDateTime,
EmailAddress = email,
Name = name
};
if (MaxAttendees.HasValue)
{
if (Rsvps.Count(r => !r.IsWaitlist) >= MaxAttendees.Value)
{
rsvp.IsWaitlist = true;
Rsvps.Add(rsvp);
return new RsvpResult("Waitlist");
}
}
Rsvps.Add(rsvp);
return new RsvpResult("Success");
}
通过将此逻辑转换为域模型,我确保我的控制器的 API 方法仍然较小并专注于其自身的问题。因此,可以轻松测试控制器是否执行它应该执行的操作,因为通过此方法创建的路径相对较少。
控制器职责
控制器的部分职责是检查 ModelState 并确保其有效。为清楚起见,我在操作方法中执行此工作,但在大型应用程序中,我会通过使用操作筛选器清除每个操作中的重复代码:
[HttpPost]
public IActionResult AddRsvp([FromBody]RsvpRequest rsvpRequest)
{
if (!ModelState.IsValid)
{
return HttpBadRequest(ModelState);
}
假定 ModelState 有效,操作下一步必须使用请求中提供的标识符来提取适当的 Dinner 实例。如果操作找不到匹配该 ID 的 Dinner 实例,它应返回“未找到”结果:
var dinner = _dinnerRepository.GetById(rsvpRequest.DinnerId);
if (dinner == null)
{
return HttpNotFound("Dinner not found.");
}
在完成这些检查后,操作即可将由请求表示的业务操作委托给域模型,调用你之前看到的 Dinner 类上的 AddRsvp 方法,并在返回 OK 响应前保存域模型的更新状态(在这种情况下,为 dinner 实例及其 RSVP 集合)。
var result = dinner.AddRsvp(rsvpRequest.Name,
rsvpRequest.Email,
_systemClock.Now);
_dinnerRepository.Update(dinner);
return Ok(result);
}
请记住,我决定 Dinner 类不应对系统时钟具有依赖关系,而选择将当前时间传入此方法。在控制器中,我为 currentDateTime 参数传入 _systemClock.Now。这是通过 DI 填充的本地字段,这还会防止控制器紧密耦合到系统时钟。
适当的做法是使用控制器上的 DI 而非域实体,因为控制器始终由 ASP.NET 服务容器创建,这将实现控制器在其构造函数中声明的任何依赖关系。_systemClock 是类型 IDateTime 的字段,只需几行代码即可定义和实现此字段。
public interface IDateTime
{
DateTime Now { get; }
}
public class MachineClockDateTime : IDateTime
{
public DateTime Now { get { return System.DateTime.Now; } }
}
当然,我还需要确保将 ASP.NET 容器配置为在类需要 IDateTime 实例时使用 MachineClockDateTime。此操作可以在 Startup 类的 ConfigureServices 中完成,在这种情况下,尽管任何对象生存期都有效,但我选择单一生存期,因为一个 MachineClockDateTime 实例将适用于整个应用程序:
services.AddSingleton<IDateTime, MachineClockDateTime>();
在准备好这个简单抽象后,我能基于 RSVP 是否过期来测试控制器的行为,并确保返回正确的结果。因为我已经对 Dinner.AddRsvp 方法进行了测试,验证其按预期方式工作,我不需要通过控制器对相同行为进行多次测试来使我确信这一点,在协同工作时,控制器和域模型都能正常工作。
后续步骤
下载关联的示例项目,查看 Dinner 和 DinnersController 的单元测试。请记住,相比充斥着依赖于基础结构问题的“新的”或静态方法调用的紧密耦合代码,松散耦合代码通常更容易进行单元测试。应该在你的应用程序中有意而不是意外使用“新关键字是粘附”和新关键字。在 docs.asp.net 上了解有关 ASP.NET Core 及其对依赖关系注入的支持。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
编程常用的几种时间戳转换(java .net 数据库).Net中关于相等的问题Asp.net MVC如何对所有用户输入的字符串字段做Trim处理Asp.Net WebForm生命周期的详解.Net开发的两个小技巧asp.net 六大内置对象.Net基础体系和跨框架开发普及Linux使用Jexus托管Asp.Net Core应用程序asp.net登录验证码实现方法ASP.NET自带对象JSON字符串与实体类的转换从 .NET 和 Java 之争谈 IT 行业.Net高效开发之不可错过的实用工具ASP.NET MVC必须知道的那些事!.NET中使用无闪刷新控件时提示框不显示.net开发中要注意的事项Asp.net Core MVC中使用Session
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南