1

在我的 asp.net mvc 控制器的构造函数中,我有多个 (5) 接口,它们以这种方式与我的数据库通信:

[HttpGet]
public ActionResult Create()
{          
 var releases = _releaseDataProvider.GetReleases();
 var templates = _templateDataProvider.GetTemplates();
 var createTestplanViewModel = new CreateTestplanViewModel(templates, releases);
 return PartialView(createTestplanViewModel);
}

上面我使用 2 个不同的接口从数据库中获取数据。

商业案例:要创建一个测试计划,我需要向用户展示他可以选择的可用版本和模板。

如何减少这两个接口的依赖/过度注入

4

3 回答 3

1

在 MVC 项目中:

public class MyController : Controller
{
    private readonly IQueryProcessor _queryProcessor;

    public MyController(IQueryProcessor queryProcessor)
    {
        _queryProcessor = queryProcessor;
    }

    [HttpGet]
    public ActionResult Create()
    {
        var releases = _queryProcessor.Execute(new ProvideReleaseData());
        var templates = _queryProcessor.Execute(new ProvideTemplateData());
        var createTestplanViewModel = AutoMapper.Mapper
            .Map<CreateTestplanViewModel>(releases);
        AutoMapper.Mapper.Map(templates, createTestplanViewModel);
        return PartialView(createTestplanViewModel);
    }
}

然后,您可以构造函数将您当前的提供者实现注入到IQueryHandler实现中。这IQueryProcessor只是基础设施。有关更多信息,请参见:https ://cuttingedge.it/blogs/steven/pivot/entry.php?id=92

回复评论:

它在我链接的网站上。这是我的:

using System.Diagnostics;
using SimpleInjector;

namespace MyApp.Infrastructure
{
    sealed class SimpleQueryProcessor : IQueryProcessor
    {
        private readonly Container _container;

        public SimpleQueryProcessor(Container container)
        {
            _container = container;
        }

        [DebuggerStepThrough]
        public TResult Execute<TResult>(IDefineQuery<TResult> query)
        {
            var handlerType = typeof(IHandleQueries<,>)
                .MakeGenericType(query.GetType(), typeof(TResult));

            dynamic handler = _container.GetInstance(handlerType);

            return handler.Handle((dynamic)query);
        }
    }
}
于 2012-08-04T20:29:17.060 回答
0

编辑

在我看来,您基本上有这些选项来减少这里的构造函数依赖计数:

  1. 拆分控制器
  2. 在两个接口前面添加层
  3. 切换到属性注入
  4. 服务定位器

#3 和 #4 被包括在内是为了很好的衡量,但它们显然并没有真正减少依赖计数,它们只是将它们隐藏在构造函数中。它们也有几个缺点,我认为服务定位器在大多数情况下尤其邪恶。

对于#1,如果您觉得您的构造函数实际上是在做两个以上的工作,并且您可以拆分的地方有一个干净的分离,我会这样做。但是,我从您的回复中假设您已经考虑过这一点,并且不想这样做。

剩下的#2 - 添加另一层。在这种情况下,将为该特定视图模型引入工厂接口。天真地,我将此命名为 ICreateTestplanViewModelFactory,但如果您愿意,您可以将其命名为对您的应用程序更有意义的名称。其上的单个方法将构造一个 CreateTestplanViewModel。

这使得该视图的数据来自 2 个来源这一事实仅仅是实现细节。您将连接一个将 IReleaseDataProvider 和 ITemplateDataProvider 作为构造函数依赖项的实现。


这与我的建议一致:

public interface IProvideTestPlanSetupModel
{
    CreateTestplanViewModel GetModel();
}

public class TestPlanSetupProvider : IProvideTestPlanSetupModel
{
    private readonly IReleaseDataProvider _releaseDataProvider;
    private readonly ITemplateDataProvider _templateDataProvider;

    public TestPlanSetupProvider(IReleaseDataProvider releaseDataProvider, ITemplateDataProvider templateDataProvider)
    {
        _releaseDataProvider = releaseDataProvider;
        _templateDataProvider = templateDataProvider;
    }

    public CreateTestplanViewModel GetModel()
    {
        var releases = _releaseDataProvider.GetReleases();
        var templates = _templateDataProvider.GetTemplates();

        return new CreateTestplanViewModel(releases, templates);
    }
}

public class TestPlanController : Controller
{
    private readonly IProvideTestPlanSetupModel _testPlanSetupProvider;

    public TestPlanController(IProvideTestPlanSetupModel testPlanSetupProvider)
    {
        _testPlanSetupProvider = testPlanSetupProvider;
    }

    [HttpGet]
    public ActionResult Create()
    {
        var createTestplanViewModel = _testPlanSetupProvider.GetModel();
        return PartialView(createTestplanViewModel);
    }
}

如果您不喜欢在控制器之外的任何地方构建视图模型,该接口可以提供一个中间对象,该对象具有您将复制到视图模型的相同属性。但这很愚蠢,因为这种数据组合仅与特定视图相关,而这正是视图模型应该表示的内容。

附带说明一下,您似乎在通过同一模型进行读/写时遇到了非常常见的烦恼。由于这些问题困扰着您,您可能会调查 CQRS,这可能会让您对直接与数据库进行这些类型的查询对话时感觉不那么脏,并且会帮助您绕过我们都非常喜欢的分层迷宫。这似乎很有希望,尽管我还没有在生产应用程序中试驾它的乐趣。

于 2012-08-04T19:40:26.250 回答
0

解耦数据库的一个很好的通用方法是使用工作单元。这是asp.net上的一篇很棒的文章,以及MSDN上的另一篇文章。

总之,您创建了一个单元,所有数据库/服务调用都驻留在其中,它可以处理数据库逻辑。这会将您的多个接口的依赖性减少到一个点,因此您只需将 1 个类注入您的控制器。

引用 MSDN 文章:

根据 Martin Fowler 的说法,工作单元模式“维护受业务事务影响的对象列表,并协调更改的写入和并发问题的解决”。

于 2012-08-04T19:46:59.747 回答