ASP.NET MVC - 当SRP和DRY似乎发生冲突时

May*_*ayo 7 asp.net-mvc controller dry single-responsibility-principle

我最简单的ASP.NET MVC 2控制器使用AutoMapper调用我的服务层并将视图模型映射到实体.一切看起来都很棒,没有重复的代码.

然而,当我进入我有类似行为的场景时,我很难平衡单一责任原则(SRP)与不重复自己(DRY).这方面的一个例子可能是需要添加/编辑车辆,其中共享某些属性/行为,而其他属性/行为是特定车辆所特有的.

如果我努力寻找真正精简的控制器(因此遵守单一责任原则),我最终会在视图和控制器中重复编码,并带有微小的变化(标题,字段标签,字段可见性,下拉值,选择标准等).

如果我努力寻找不重复的代码,我最终会将过多的逻辑捆绑到一个控制器/视图中,并且它会变得臃肿.

在控制器/视图中解决重复代码的方法有哪些?我不是在谈论可以分解到存储库的数据库代码.我也不是在谈论可以考虑到服务层的业务逻辑.我正在寻找可以帮助我在上述场景中产生最佳解决方案的工具和/或经验法则.

que*_*en3 3

你得到:

  • 部分
  • 渲染动作
  • 动作过滤器
  • 服务层和帮助程序类(不是 HtmlHelper)
  • 模型活页夹
  • 基地控制器
  • 依赖注入

因此,您的视图可以调用类似部分的共享部分/操作,可以通过操作过滤器准备公共数据,可以将数据库访问代码隐藏在智能模型绑定器中,或者您可以拥有子控制器通过特定调整覆盖的父控制器。当然,还有很好的旧服务层,您只需将通用代码提取到帮助器/静态方法中,或者更好的是注入特定的实现。

这不是什么新鲜事,都是老套路。

或者,也许您的控制器做了太多工作?这就是上面的内容也有帮助的地方。ASP.NET MVC 有非常好的工具来隐藏基础结构层代码并将其移离控制器。如果它不是基础设施 - 它可能属于域层。在那里您可以使用继承、组合和其他 OOP 技巧。

具体例子。假设您的控制器应该以不同的方式设置一些属性。

  1. 如果主要是格式化或选择要显示的属性,您可以让视图来执行此操作
  2. 您可以让您的实体拥有虚拟方法 - 即重构代码以将决策移至域层而不是控制器
  3. 您可以使用辅助 ViewDetails 类来获取您的实体并根据您的需要获取数据;这是一个有点肮脏的把戏,但有时很有用;您将决策委托给另一个“策略”类
  4. 您可以使用操作过滤器将此数据添加到 ViewData,或调整特定的 ViewData.Model 类型(查找它的某些接口)。
  5. 您可以拥有抽象控制器,其中子级将实现细节传递给基本构造函数,例如 ():base(repository =>repository.GetSpecificData())

等等。实际上我在适当的地方使用了它们。