【问题标题】:Autofac constructor/property injection (DbContexAutofac 构造函数/属性注入(DbContext
【发布时间】:2018-04-23 10:46:06
【问题描述】:

我开始使用 DI/IoC,但在理解所有概念时遇到了一些麻烦。

我之所以选择 Autofac,是因为它似乎是少数同时支持 .Net 4.6+ 和 .Net Core 的公司之一。它似乎也是使用最广泛的。

1) 构造函数注入 - 例如在控制器或我的 WCF 服务中 我知道不可能对我在代码中实例化的对象进行构造函数注入,这意味着它不会自动实例化。

2) 属性注入 我想做一些类似于你在 Ninject 中做的事情:

[Inject]
public IWeapon Weapon { get; set; }

据我所知,在 Autofac 中。它等同于:

builder.RegisterType<Weapon>().As<IWeapon>().PropertiesAutowired();

1.现在,为什么构造函数注入是首选方式?

例如,我有:

  • 存储库工厂
  • 商业引擎工厂

那些工厂只是单线,应该做类似(来自另一个 IoC)的事情:

public class DataRepositoryFactory : IDataRepositoryFactory
{
    T IDataRepositoryFactory.GetDataRepository<T>()
    {
        return ObjectBase.Container.GetExportedValue<T>();
    }
}

有些方法需要两者,有些则不需要。做类似的事情:

public SampleControllerOrManager(IUnitOfWork unitOfWork, IRepositoryFactory repositoryFactory, IBusinessEngineFactory engineFactory)

似乎是在浪费资源。

我知道这有助于测试 (?)。

但这看起来更干净:

public SampleControllerOrManager(IUnitOfWork unitOfWork)

[Inject]
public IRepositoryFactory RepositoryFactory { get; set; }

[Inject]
public IBusinessEngineFactory EngineFactory { get; set; }

2。将实体框架 DbContext 注入存储库

我想用 Container 注册上下文并将其注入到 UnitOfWork 和 Repository 的对象构造函数中。我想确保将相同的实例注入到所有对象中。我如何在 Autofac 中做到这一点?

    public class Repository : IRepository {
        //context injected here
        public Repository (DbContext context){ ... }
    }

    public class Manager {
        public void SomeMethod(){
            IRepository = RepositoryFactoryGetDataRepository<ISomeTypeRepository>
        }
    }

【问题讨论】:

    标签: c# entity-framework inversion-of-control autofac ioc-container


    【解决方案1】:

    构造函数注入

    构造函数注入是首选方式,因为它使它们显而易见。如果不提供所需的依赖项,则无法实例化该类。

    通过属性注入,依赖项被隐藏,您可以用一些缺失的注入来实例化该类,这可能使您相信该类已完全初始化并可以使用。最终,如果您尝试使用需要缺少依赖项的功能,您可能会收到错误。

    实例范围

    为确保注入相同的实例,您可以将您的 DbContext 注册为 Singleton。 例如:

    var builder = new ContainerBuilder();
    builder.RegisterType<DbContext>().SingleInstance();
    

    或者,根据您的需要,您可以使用 Instance Per Request 范围注册它:

    var builder = new ContainerBuilder();
    builder.RegisterType<DbContext>().InstancePerRequest();
    

    注意:您可能会发现 Martin Fowler 编写的 this article 很有用。

    【讨论】:

    • 就像我在第 1 页中的示例一样,如果不是所有的依赖项总是需要怎么办?
    • 因为它们不是在类的每个方法中都使用,并不意味着它们是可选的。它们仍然是对象完全工作所必需的。
    • DbContext 不能是单例,它反对一切。管理器/控制器是每个请求的,这意味着每次请求操作时都会创建新实例。在该操作的范围内,应该将一个 DbContext 注入到内部请求的每个存储库中。我想我应该使用“per life scope”之类的东西。
    • 它有时很有用,例如,当您使用为您实例化类但不允许您提供自定义工厂来完成工作的框架时。如果没有属性注入,您将无法注入所需的依赖项。在我看来,这更像是一种解决方法。如果可能,您应该使用构造函数注入。如果没有,请使用属性注入。
    • 不,工厂模式不是一个坏习惯。依赖关系没有隐藏,任何希望实例化工厂的人都可以看到它们。我想说,将职责委派给特定的类是一种非常好的做法,并且是 SOLID 的第一原则。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多