繁体   English   中英

使用Autofac动态解决依赖关系

[英]Resolving dependencies dynamically using Autofac

像我正在做的那样动态地解决依赖关系是否很好。 建议在任何地方都使用构造函数注入。 我真的不明白我这样做的弊端。 代码片段如下。

Employee.cs

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public Department Department { get; set; }
}

IRepository.cs

public interface IRepository<TModel> where TModel : class
    {
        void Add();
        IEnumerable<TModel> GetAll();
        IEnumerable<TModel> GetByID();
    }

Repository.cs

public class Repository<TModel> : IRepository<TModel> where TModel : class
{
    public void Add()
    {
        throw new NotImplementedException();
    }

    public IEnumerable<TModel> GetAll()
    {
        throw new NotImplementedException();
    }

    public IEnumerable<TModel> GetByID()
    {
        throw new NotImplementedException();
    }
}

EmployeeController.cs

public class HomeController : ApiController
{
    IComponentContext _container;

    public HomeController(IComponentContext container)
    {
        this._container = container;
    }

    public Repository<TModel> Using<TModel>() where TModel :class
    {
        var repository = _container.Resolve(typeof(IRepository<TModel>));
        return repository as Repository<TModel>;
    }

    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return Using<Employee>().GetAll();
    }
}

Global.asax中

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);

    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));

    var container = builder.Build(Autofac.Builder.ContainerBuildOptions.None);
    var webApiResolver = new AutofacWebApiDependencyResolver(container);
    GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
}

假设我有5个存储库,构造函数注入将解决我提出的所有5个依赖关系。 对于每个请求,我可能不会使用5个存储库。 所以我想到了通过像在Using<TModel>()那样传递类型来动态地解决依赖关系。 任何建议,将不胜感激..!! 谢谢...!!

不要在应用程序组件内部直接使用容器; 这会导致各种麻烦,例如可维护性和可测试性问题。 从应用程序代码中直接解析实例是众所周知的反模式,称为Service Locator

作为第一个重构,您可以改为应用工作单位模式。 工作单元允许访问基础存储库。 例如:

public interface IUnitOfWork
{
    IRepository<TModel> Repository<TModel>();
}

public sealed class HomeController : ApiController
{
    private readonly IUnitOfWork _unitOfWork;

    public HomeController(IUnitOfWork unitOfWork)
    {
        this._unitOfWork = unitOfWork;
    }

    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return this._unitOfWork.Repository<Employee>().GetAll();
    }
}

现在,在“ 合成根目录”允许访问容器的位置)内,我们可以创建一个IUnitOfWork实现,以动态解析存储库:

private sealed class AutofacUnitOfWork : IUnitOfWork
{
    private readonly IComponentContext _container;

    public AutofacUnitOfWork(IComponentContext container)
    {
        this._container = container;
    }

    public IRepository<TModel> Repository<TModel>()
    {
        return _container.Resolve<IRepository<TModel>>();
    }
}

此模式大大简化了您的应用程序组件,并避免了Service Locator反模式通常造成的不利影响。

尽管应用工作单元模式可能是朝正确方向迈出的有用一步,但更好的方法是直接跳过工作单元,而直接将所需的存储库直接注入到应用程序组件中:

public sealed class HomeController : ApiController
{
    private readonly IRepository<Employee> _employeeRepository;

    public HomeController(IRepository<Employee> employeeRepository)
    {
        this._employeeRepository = employeeRepository;
    }

    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return this._employeeRepository.GetAll();
    }
}

假设我有5个存储库,构造函数注入将解决我提出的所有5个依赖关系。 对于每个请求,我可能不会使用5个存储库。

请注意,从性能角度来看,通常不必担心是否使用了依赖项。 Autofac在大多数情况下足够快,这不太可能在生产系统中实际引起任何性能问题。

但是从设计角度来看,您应该更担心类是否具有许多依赖关系,而方法仅使用其中的一些依赖关系。 这意味着该类中的方法几乎没有凝聚力。 这表明该类应划分为多个较小的类。 它有多种职责

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM