在我的asp.net mvc controller的构造函数中,我有多个(5)接口以这种方式与我的数据库通信:
[HttpGet]
public ActionResult Create()
{
var releases = _releaseDataProvider.GetReleases();
var templates = _templateDataProvider.GetTemplates();
var createTestplanViewModel = new CreateTestplanViewModel(templates, releases);
return PartialView(createTestplanViewModel);
}
上面我使用2个不同的接口从数据库中获取数据。
业务案例:要创建测试计划,我需要向用户显示他可以选择的可用版本+模板。
如何减少这两个接口的依赖性/过度注入
答案 0 :(得分: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);
}
}
}
答案 1 :(得分:0)
修改强>
在我看来,你基本上有这些选项来减少构造函数依赖计数:
对于#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,这可能会让您感觉不那么直接与数据库进行这些类型的查询交流,并且可以帮助您绕过我们都非常喜欢的分层迷宫。虽然我还没有在测试中将其驱动到生产应用程序中,但它似乎很有希望。
答案 2 :(得分:0)