Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在MVC中使用DI时的大量控制器构造函数参数列表_C#_Asp.net Mvc 3_Dependency Injection_Autofac - Fatal编程技术网

C# 在MVC中使用DI时的大量控制器构造函数参数列表

C# 在MVC中使用DI时的大量控制器构造函数参数列表,c#,asp.net-mvc-3,dependency-injection,autofac,C#,Asp.net Mvc 3,Dependency Injection,Autofac,我正在开发ASP.NET MVC3解决方案,该解决方案使用autofac的依赖项注入。 我们的控制器是由autofac创建的,所有必需的对象都被正确地传入。这些对象通常包括将域对象转换为MVC(视图)模型的服务、存储库和映射器。因此,控制器构造函数看起来有点像: public abcController( ILogger logger, IabcRepository abcRepository, IabcService abcService,

我正在开发ASP.NET MVC3解决方案,该解决方案使用autofac的依赖项注入。 我们的控制器是由autofac创建的,所有必需的对象都被正确地传入。这些对象通常包括将域对象转换为MVC(视图)模型的服务、存储库和映射器。因此,控制器构造函数看起来有点像:

public abcController(
        ILogger logger,
        IabcRepository abcRepository,
        IabcService abcService,
        IMapper<AbcDomain, AbcViewModel> abcMapper,
        ...
        )
公共ABC控制器(
ILogger记录器,
我相信,
IabcService abcService,
伊玛珀,
...
)
不幸的是,随着时间的推移,这些构造函数参数列表往往会快速增长。我们的一些控制器现在期望60个或更多参数

我们在这里创建了一些反模式吗

编辑

我应该提到的是,我们试图遵循瘦控制模式。此外,这些参数中的大多数往往是映射器,约占66%。控制方法通常非常简单,并遵循以下模式之一:

  • 根据参数调用适当的服务或存储库
  • 使用映射器将结果转换为适当的视图模型
  • 将视图模型传递到视图
或者这种模式:

  • 从post操作接收模型
  • 使用映射器将其转换为适当的域对象
  • 使用域对象调用适当的服务或存储库
(免责声明:此答案与参数列表的大小有关。它不会减少控制器内的依赖关系)

在这种情况下,您将注入一个工厂

例如:

interface IABCFactory {
    ILogger CreateLogger();
    IABCRepository CreateRepo();
    // .. etc
}
然后,您的构造函数变成:

private ILogger _logger;

public abcController(IABCFactory factory) {
    _logger = factory.CreateLogger();
    // .. etc
}

注意,您可以将注入到公共属性中。。但这取决于你是否想让外界知道。如果您不想破坏封装,那么您可以选择工厂。

60个或更多的参数是很多的

在您的问题中,您提到“.这些对象通常包括服务、存储库和将域对象转换为MVC(视图)模型的映射器…”

你有一个胖控制器(不是任务引擎类型的Thomas),但是一个做得太多的控制器

我寻找的平衡是胖型瘦控制器。伊恩·库珀在这篇文章中谈得很好

您还可以查看诸如哪些参数实际上是交叉切割关注点之类的内容


例如,在我看来,映射和日志记录是交叉关注点,因此您可以潜在地使用动作过滤器来清理控制器

如果这很大程度上取决于创建视图模型,那么这个问题和答案可能会有所帮助

我还要看看曼宁的MVC4。它包括创建自动映射的ActionResult

在我的应用程序中,大多数控制器操作都是一行的。拉取实体并将其传递给自动映射和丰富viewresult,或者接收命令并将其传递给处理该实体的操作结果

Jimmy的这篇博文涵盖了博文的一些方面

基本上,我得到一个域对象(来自repo或其他方法),并返回一个自动映射的视图结果,该结果映射到相应的VM

return AutoMappedView<ExaminationCreateModel>(new Examination ( _assetRepository.Find(assetId)));
返回autompedview(新检查(_assetRepository.Find(assetId));
然后,mapper ViewResult将其传递给enricher(如果发现一个enricher实现了IModelEnricher)。请参阅其他堆栈问题

在返回时,它作为命令发回,然后该命令的处理有点像Bogard post

    public virtual ActionResult Create(AddAssetExaminationCommand addAssetExaminationCommand, ICommandHandler<AddAssetExaminationCommand> addExaminationHandler) 
    {
        return ProcessForm(
            addAssetExaminationCommand,
            addExaminationHandler,
            RedirectToAction(MVC.OnboardAsset.Examinations.Create()),
            RedirectToAction(MVC.OnboardAsset.Examinations.Index(addAssetExaminationCommand.AssetId)));
    }

公共虚拟操作结果创建(AddAssetExaminationCommand AddAssetExaminationCommand,ICommandHandler)因此错误仍然存在。如果命令处理程序处理它是有效的,我们重定向到一个成功页面

,我真的无法谈论您应该如何重新构建控制器,尽管我同意大多数其他答案-60个传入参数太多了

Autofac拥有的功能可能有助于减少参数数量,但不会减少依赖项数量

与直接获取60个参数不同,您可以获取一个具有60个属性的聚合参数

您创建了一个具有依赖项的接口(只是接口,实际上不必实现它):

public interface IMyAggregateService
{
  IFirstService FirstService { get; }
  ISecondService SecondService { get; }
  IThirdService ThirdService { get; }
  IFourthService FourthService { get; }
}
然后修改控制器以获取该聚合接口:

public class SomeController
{
  private readonly IMyAggregateService _aggregateService;

  public SomeController(
    IMyAggregateService aggregateService)
  {
    _aggregateService = aggregateService;
  }
}
您可以注册聚合服务接口、依赖项和控制器,当您解析控制器时,聚合服务接口将自动为您实现和解析

var builder = new ContainerBuilder();
builder.RegisterAggregateService<IMyAggregateService>();
builder.Register(/*...*/).As<IFirstService>();
builder.Register(/*...*/).As<ISecondService>();
builder.Register(/*...*/).As<IThirdService>();
builder.Register(/*...*/).As<IFourthService>();
builder.RegisterType<SomeController>();
var container = builder.Build();
var builder=newcontainerbuilder();
builder.RegisterAggregateService();
builder.Register(/*…*/).As();
builder.Register(/*…*/).As();
builder.Register(/*…*/).As();
builder.Register(/*…*/).As();
RegisterType();
var container=builder.Build();
同样,它也没有涉及到需要如此多依赖项的更大问题,但是如果您只是想简化构造函数和控制器上的属性数量,以便更易于管理,这是Autofac提供的一种策略,可以在这方面提供帮助


您可以使用
按属性注入
而不是
按构造函数注入
@HamletHakobyan-Hmmm…这可能会起作用,我必须尝试看看它如何与autofac一起工作。我可以看到这个解决方案在单元测试方面的好处。为什么不回答这个问题。autofac还支持动作注入请参见此处。因此,一个操作只需要一个参数就可以这样做。60仍然是很多:)根据一般经验,构造函数的依赖项不应超过5个。60个依赖项是依赖项数量的12倍。您如何测试一个具有60个依赖项的类?您可能会从分组中受益。史蒂文斯代码是我大量架构的基础。它真的清理了我的代码+Jimmy Bogard的一些映射东西,各种自定义ActionResults和一些自定义ModelEnricher工作。你不是刚把一长串参数移出了控制范围吗