控制器瘦身的艺术

在2010年的一次.NET伦敦小组会议上,简短地讨论了一个话题,这让深思熟虑。在自己的项目中开始实践,现在,有足够的信心来分享想法。以下是观点,如果同意或不同意,请在评论中告诉。

一定听说过:“控制器不应该臃肿,控制器应该包含最少的代码”,这是一条准则。在SOLID原则中,S代表单一职责原则(SRP)。控制器应该只有一个角色,它是模型和视图之间的通信层。即使在这个角色中,它也违反了SRP,有人可能会说,也许需要两个类来承担控制器的角色,或者每个动作方法一个控制器,但先不深入讨论这个问题。

控制器的角色本身就承担了过多的责任,再给它增加更多的责任就是设计上的罪过(也许应该因为这样做而失去一些StackOverflow或CodeProject的积分)。

为什么控制器会变胖?之前写过一篇博客,讨论了视图如何变得臃肿:,其中一些观点是通用的,一些是特定于控制器的:

在动作方法中显式验证数据 在控制器中验证视图模型数据违反了两个原则:单一职责原则(SRP)和封装的面向对象原则(OOP)。ASP.NET MVC 4提供了一个很好的验证生态系统,可以帮助将验证代码移到它应该在的地方。

映射模型到视图模型 模型到视图模型的映射不应该在动作方法中进行。最喜欢的解决方案是使用CQRS类型的查询模式,这样就不需要在任何地方进行这种样板代码。这里有一个关于CQRS的很好的。

泄露一些业务逻辑 这里不是放置任何业务逻辑的地方。控制器应该调用服务,或者是经典领域驱动设计(DDD)的实现,或者是发出CQRS的查询或命令。

动作方法中的HTTP相关代码 需要特殊处理的特殊HTTP案例不应该在这里完成。动作过滤器可能是答案。

在单元测试什么? 鉴于上述情况,如果动作方法几乎没有代码,那么在单元测试什么?想测试是否返回了正确的视图,还是想测试是否用正确的属性装饰了动作方法?不会这样做,通常有一个截止日期要达到,反对样板代码。

如果有人告诉他们的控制器需要单元测试,会问,设计控制器的方式正确吗?

结论:单元测试是提供更高质量软件的手段,而不是目的本身。有太多的冗余单元测试会导致未来的维护问题,并且会增加项目开发时间。

// 示例代码,展示如何使用CQRS模式 public class QueryHandler : IQueryHandler { private readonly IRepository _repository; public QueryHandler(IRepository repository) { _repository = repository; } public ProductViewModel Handle(GetProductQuery query) { var product = _repository.Get(query.ProductId); return product == null ? null : new ProductViewModel { ProductId = product.ProductId, Name = product.Name, Price = product.Price }; } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485