【问题标题】:ASP.NET MVC - Service layer, single or many services in each controller action?ASP.NET MVC - 服务层,每个控制器动作中的单个或多个服务?
【发布时间】:2012-06-06 11:48:38
【问题描述】:

我开始在我的 MVC 项目中实现一个服务层来精简一些臃肿的控制器(它也有存储库/工作单元模式)。

我的问题是,如果您的页面有一个复杂的视图模型,其中包含大量子对象等,并且在幕后进行了大量逻辑(让您了解原始开发人员编写的控制器有近 4000 行代码!!)可以让多个服务停止工作吗?还是我应该只拥有一个可以完成所有工作的大型 ReportService?

我的控制器开始看起来像这样?如果我继续下去,我最终可能会调用很多不同的服务来构建视图模型。

这看起来不错,还是开始朝错误的方向发展?

public ViewResult Index(int? reportId)
    {
        // get the base report object
        var reportService = new ReportService();
        var report = reportService.GetByReportId(reportId);
        var model = Mapper.Map<Report, ReportViewModel>(report);

        // get the current active user
        var userService = new UserService();
        var user = userService.GetCurrentUser();
        model.User = Mapper.Map<User, ReportViewModel.UserViewModel>(user);

        // get the first unread message
        var messageService = new MessageService();
        var message = messageService.GetFirstUnread(user.Id);
        model.Message = Mapper.Map<Message, ReportViewModel.MessageViewModel>(message);

        // get the category navigation
        var categoryService = new CategoryService();
        var categoryNavigation = categoryService.GetCategoryNavigation(report.Id);
        model.CategoryNavigation = Mapper.Map<IEnumerable<Category>, IEnumerable<ReportViewModel.CategoryNavigationViewModel>>(categoryNavigation);

        return View(model);
    }

【问题讨论】:

  • 实际上看起来很干净。控制器方法应该被认为是“补丁面板”,几乎没有或没有业务逻辑。这里就是这种情况。很明显,您在同一页面上显示来自不同来源的不同类型的信息(很像“仪表板”视图),所以我在这里看到的相对复杂性是完全合理的。
  • 如果您担心它的复杂性,您可以考虑通过 Ajax 加载每个值并返回部分视图并为每个服务设置一个操作等。这样,如果需要,您可能会拆分您的控制器。

标签: asp.net-mvc asp.net-mvc-3


【解决方案1】:

在您的控制器中有多个小型服务很好。但是,这里有一个问题:

你的服务应该通过整个控制器可用,并通过构造函数注入以实现松耦合。

所以是这样的:

private readonly IReportService _reportService;
private readonly IUserService _userService;

public SomeConstructor(IReportService reportService, IUserService userService, etc.) 
{
    _reportService = reportService;
    _userService = userService;
    // etc
}

【讨论】:

  • 取决于需要多少服务 - 例如,如果您查看的服务数量超过 6-8 个,那么实现按需依赖解决可能会更好,以避免使用具有大量参数的构造函数.尽管如此 +1 tho
  • 你是对的。但是,当您需要数十种服务时,这可能表明您应该将控制器“拆分”为不太通用的控制器。
【解决方案2】:

这看起来确实是一个不错的方法,另一种方法是使用子操作将其中的一部分拆分 - 不过最好的解决方案将取决于您的具体用例。

例如,如果视图使用 ViewModel 属性 CategoryNavigation 来创建一种可能在多个不同视图中有用的导航“小部件”,则最好将其拆分为 ChildAction,例如

[ChildActionOnly]
public ActionResult CategoryNavigationWidget(int reportId)
{
    // get the category navigation
    var categoryService = new CategoryService();
    var categoryNavigation = categoryService.GetCategoryNavigation(report.Id);

    return PartialView(categoryNavigation);
}

然后任何 View 都可以通过以下方式呈现该 ChildAction:

   @{ Html.RenderAction("CategoryNavigationWidget", "Report", 
           new { reportId = Model.ReportId }); }

这是否是一个好主意可能取决于“小部件”是否可重复使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    相关资源
    最近更新 更多