在MVC使用DI当海量的控制器构造函数的参数列表(Massive controller constr

2019-08-08 05:04发布

我正在使用依赖注入autofac ASP.NET MVC3解决方案。 我们的控制器正在autofac和创建正确和所有必需的对象在被正确地传递,这些对象通常包括服务,知识库,映射器域对象转换为MVC(视图)模型。 因此,控制器构造颇像:

public abcController(
        ILogger logger,
        IabcRepository abcRepository,
        IabcService abcService,
        IMapper<AbcDomain, AbcViewModel> abcMapper,
        ...
        )

不幸的是,假以时日,这些构造函数的参数列表往往相当迅速成长。 我们的一些控制器目前预计60个或多个参数。

难道我们在这里创建了一些反模式?

编辑

我应该提到,我们尽量按照薄位指示模式。 另外大多数这些参数往往是映射器 - 66%左右。 控制方法通常非常简单,要么遵循这个模式:

  • 基于参数调用相应的服务或资源库
  • 使用映射到结果转换为相应的视图模型
  • 通过视图模型查看

或者这样的模式:

  • 接收来自POST操作模式
  • 使用映射器将其转换为appropiate域对象
  • 调用相应的服务或资源库和域对象

Answer 1:

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

在你的问题,你说“..Those对象通常包括服务,知识库,映射器域对象转换为MVC(视图)模型......”

你已经有了一个肥胖控制器(不是托马斯任务引擎的那种),但它们已经做了太多的控制器。

平衡我寻找的是脂肪模型瘦控制器。 伊恩·库珀谈论它以及在此博客文章

您还可以看看,比如哪种参数实际上交叉扦插关注。

例如映射和日志记录在我的脑海里是横切关注点,所以你可能会使用操作过滤器来清理你的控制器。



Answer 2:

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();

再次,它并不需要很多的依赖较大的问题发言,但如果你只是希望简化你的构造和控制器,以便它更易于管理的特性数量,这是一个战略Autofac提供在帮助。

退房的wiki页面了解更多详情。



Answer 3:

如果有很多的,这是下跌创造的ViewModels这个问题,答案可能有帮助。

MVC -控制器具有多种选择列表

我也想看看MVC 4从曼宁行动。 它涵盖了创建自动映射一个ActionResult。

在我的应用我的大部分控制动作一行。 或者拉动一个实体,它传递给一个自动映射和丰富的ViewResult或取入的命令,并将其传递给处理它的操作结果

这从吉米的博客文章讲述了一些POST侧的http://lostechies.com/jimmybogard/2011/06/22/cleaning-up-posts-in-asp-net-mvc/

基本上我得到一个域对象(从回购或其他方法),并用映射到适当的虚拟机中automapped视图结果返回。

return AutoMappedView<ExaminationCreateModel>(new Examination ( _assetRepository.Find(assetId)));

映射器的ViewResult然后将其传递到富集(如果找到一个实施IModelEnricher见其他堆问题。

在返回时则回发一个命令,命令将被处理的有点像博加德岗位。

    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)));
    }

如果失败的验证,然后重定向到GET和ModelState中的(使用类似PRG模式合并本 )这样的错误仍然存在。 如果是用它有效的命令处理程序的交易,我们重定向到成功页面



Answer 4:

(免责声明:本答案是关于参数列表的大小,它不会降低控制器内的依赖性。)

在这种情况下,你会注入一个厂。

例如:

interface IABCFactory {
    ILogger CreateLogger();
    IABCRepository CreateRepo();
    // .. etc
}

你的构造就变成了:

private ILogger _logger;

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

注意,你可以注入公共属性..但它是你是否要公开该到外面的世界。 如果你不想破坏封装,然后你会去一个工厂。



文章来源: Massive controller constructor argument list when using DI in MVC