首页 > 解决方案 > 将业务逻辑与控制器的依赖关系解耦的正确方法

问题描述

我对 ASP.Net MVC 生疏了,并且正在努力寻找正确的方法来解决我在继承的一个大型项目中遇到的情况。该应用程序具有大量控制器,这些控制器最初在其角色中定义良好。随着应用程序的增长,我遇到了它们之间功能重叠增加的问题。

例如,现在有一个 Dashboard 控制器,它为用户提供整个应用程序其余部分发生的关键参数的概览。因此,该控制器依赖于许多依赖项来填充视图。它还对仪表板所需的数据执行大量业务逻辑/计算。现在我们有了新的附加要求,即在应用程序过程中的关键里程碑处将这些相同的值归档到数据库中。这在使用仪表板视图时效果很好(它使用 ajax 并经常调用更新)——当我们达到这些里程碑时,我可以让它根据需要存储值。

但是当仪表板没有被使用时——并且没有调用仪表板视图/控制器时,我们仍然需要在里程碑处存储数据。我不想在可能会遇到各种里程碑的每个其他控制器中复制相同的逻辑,但我正在努力用所有必要的依赖项来抽象它。处理这个问题的最佳方法是什么?

[Authorize]
public class DashboardController : SdControllerBase
{
    private readonly ICoLabAssembler _assembler;
    private readonly ICoLabDataMapper _colabDataMapper;
    private readonly IClusterAssembler _clusterAssembler;
    private readonly IClusterDataMapper _clusterDataMapper;
    private readonly IStatementDataMapper _statementDataMapper;
    private readonly IStatementAssembler _statementAssembler;
    private readonly IActiveCoLabIdService _activeCoLabIdService;
    private readonly IIsmAlgorithmAdapterService _ismAdapter;
    private readonly IPrioritizationVoteActionDataMapper _prioritizationVoteActionDataMapper;
    private readonly IVoteDataMapper<PrioritizationVote, Participant> _prioritizationVoteDataMapper;
    private readonly IPrincipal _currentUser;
    private readonly SdContext _context;

    private int? _activeColabId;
    protected int ActiveColabId
    {
        get
        {
            _activeColabId = _activeColabId ?? _activeCoLabIdService.GetColabId();
            return _activeColabId.Value;
        }
    }

    public DashboardController(ICoLabAssembler assembler, ICoLabDataMapper dataMapper, 
        IClusterAssembler clusterAssembler, IClusterDataMapper clusterDataMapper,
        IStatementDataMapper statementDataMapper, IStatementAssembler statementAssembler,
        IActiveCoLabIdService activeCoLabIdService, IPrioritizationVoteActionDataMapper prioritizationVoteActionDataMapper, 
        IVoteDataMapper<PrioritizationVote, Participant> prioritizationVoteDataMapper, IPrincipal currentUser, IIsmAlgorithmAdapterService ismAdapter, SdContext context)
    {
        _assembler = assembler;
        _colabDataMapper = dataMapper;
        _clusterAssembler = clusterAssembler;
        _clusterDataMapper = clusterDataMapper;
        _statementDataMapper = statementDataMapper;
        _statementAssembler = statementAssembler;
        _activeCoLabIdService = activeCoLabIdService;
        _prioritizationVoteActionDataMapper = prioritizationVoteActionDataMapper;
        _prioritizationVoteDataMapper = prioritizationVoteDataMapper;
        _currentUser = currentUser;
        _ismAdapter = ismAdapter;
        _context = context;
    }
    
    public async Task<ActionResult> Index()
    {
        var model = await buildDashboardViewModelAsync();   

        return View(model);
    }

    [HttpPost]
    public async Task<JsonResult> getDashboardAllData(int coLabID = 0)
    {
        var model = await buildDashboardViewModelAsync(coLabID);
        return Json(model, JsonRequestBehavior.AllowGet);
    }

    private async Task<CoLabDashboardViewModel> buildDashboardViewModelAsync(int coLabID = 0)
    {
        //Lots of business logic here that uses the dependencies above
        
        return model;
    }

标签: c#asp.net-mvc

解决方案


如果我可以从其他各种控制器调用仪表板控制器,我也许可以制定一个可行的解决方案,如果不是最优雅的。遵循这个答案:如何从 Mvc 中的控制器调用另一个控制器操作

添加到我的仪表板控制器:

public async void calculateMilestoneValues(int coLabID = 0)
{
    //Used to calcualte and stored milestone values from other controllers.
    var model = await buildDashboardViewModelAsync(coLabID);
    return;
}

编辑:在弄清楚该项目已经在使用 Castle Windsor 之后,我终于能够得到一个可行的解决方案。我仍然需要为其设置一些额外的组件来解决依赖关系,但随后能够从其他控制器调用 DashboardController 中所需的功能:

//Call dashboard controller so it can save milestone data to db if needed
var dashboardController = ServiceLocator.GetContainer().Resolve<DashboardController>();
DashboardController.CalculateMilestoneValues(viewModel.CoLabId);

所以这并没有真正从控制器中抽象出功能,但它确实为我提供了一种调用它的方法,而无需将其复制到其他控制器中。


推荐阅读