【问题标题】:MVC 3 Generic Repositories Injection with Autofac使用 Autofac 进行 MVC 3 通用存储库注入
【发布时间】:2012-05-07 09:30:21
【问题描述】:

问题出在: 我正在研究使用通用存储库的解决方案,存储库工作正常等等。问题是我试图重构代码以启用对控制器构造函数的注入依赖项。为什么我要实现这个?,解决方案使用 TDD,我们希望简化应用程序的测试方式。我不想像我们实际做的那样创建假货,而不是我真的想利用 EF 存储库的好处并在编译时解决,如果我使用 FakeRepository(在级别实体进行更改)和真正的存储库使更改数据库。

我使用 EF 作为持久化技术。

这些行代表存储库

public class Repository<T> : IRepository<T> where T
                                : class, IEntity
{
    private readonly DbSet<T> dbset;
    private readonly DbContext _context;

    public Repository(DbContext context)
    {
        _context = context;
        dbset = context.Set<T>();
    }

    public void Add(T entity)
    {
        //Some logic...
    }

    public void Update(T entity)
    {
        //Some logic...
    }

    //more methods...

}

这些行代表假存储库

    public class FakeRepository<T> : IRepository<T> where T
                                : class, IEntity
{
    private readonly DbSet<T> dbset;
    private readonly DbContext _context;

    public FakeRepository(DbContext context)
    {
        _context = context;
        dbset = context.Set<T>();
    }

    public void Add(T entity)
    {
        //Some logic...
    }

    public void Update(T entity)
    {
        //Some logic...
    }

    public void Remove(T entity)
    {
        //Some logic...
    }

    //more methods...
}

这些行代表存储库的接口契约。

public interface IRepository<T>
                    where T : class, IEntity
{
    void Add(T entity);
    void Remove(T entity)
    void Remove(T entity);
    //more methods...
}

这是一个控制器示例,它的构造函数需要 previos 类型的 Generic。

public class DemoController : Controller
{
    private readonly IRepository<IEntity> _repository;
    public DemoController(IRepository<IEntity> repository)
    {
        _repository = repository;
    }

    public ViewResult Index()
    {
        return View(_repository.FindAll());
    }

}

所以,问题是......我如何在 Autofac 容器上注册类型。我看到很多关于如何实现这一点的论坛,但没有找到解决这个需求的方法。

在 global.asax 中试过这个:

    protected void Application_Start()
    {
        ConfigureIoC();
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

    private static void ConfigureIoC()
    {
        var builder = new ContainerBuilder();
        builder.RegisterControllers(typeof(Global).Assembly);

        //At this section the dependencies are added in order to resolve Types.
        builder.RegisterType<MyController>().InstancePerHttpRequest();

        builder.RegisterType<MyContext>().As<DbContext>();
        builder.RegisterType<Repository<Entity>>().As<IRepository<IEntity>>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

我也尝试注册单个类型,但 autofac 根本不知道如何解析控制器构造函数。

提前致谢!

【问题讨论】:

  • 我也尝试了下一个方法,但出现错误:builder.Register>(x => new Repository(new DbContext())).As>();如果我运行此代码,我得到的错误如下:类型“CHR.Data.Common.Repository.Metadata.MetadataRepository`1[CHR.Model.Metadata.ExaminationElement]”不可分配给服务任何建议?

标签: asp.net-mvc-3 generics dependency-injection repository-pattern autofac


【解决方案1】:

您将IRepository&lt;IEntity&gt; 注入DemoController,这很奇怪,因为IEntity 不是具体实体,而DemoController 可能需要具体实体(例如Customer)。由于您要将IRepository&lt;T&gt; 映射到具体的Repository&lt;T&gt;,因此您需要进行以下注册:

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

您可能还需要根据 Web 请求或在生命周期范围内注册 DbContext。将MyController 注册为PerHttpRequest 似乎很奇怪。

【讨论】:

  • 谢谢 steven,我将 InstancePerHttpRequest 子句添加到我的代码中遗漏的 db 上下文中。我正在尝试您的解决方案。
【解决方案2】:

感谢史蒂文的建议。看到文档和其他一些博客,我找到了一个我分享的解决方案。 我也将尝试您的替代方法来检查哪种方法比其他方法更快。

基于泛型焦点解决构造器注入的代码如下:

    protected void Application_Start()
    {
        ConfigureIoC();
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

    private static void ConfigureIoC()
    {
        var builder = new ContainerBuilder();
        builder.RegisterControllers(typeof(Global).Assembly);

        //First we register the types for DemoController.
        builder.RegisterType<Repository<Entity>>().As<IRepository<IEntity>>();
        //Then we register the controller itself resolving/indicating the target type to use on the constructor.
        builder.Register(c => new DemoController(c.Resolve<IRepository<IEntity>>()));

        //We build the container.
        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

还有另一种方法使用 autofac 的另一种方法,但是由于以前的方法自动解决了依赖关系,它就足够了。我把方法放上来供参考

            builder.RegisterType(typeof(DemoController)).UsingConstructor(typeof(IRepository<IEntity>));

我还分享了一个链接,您可以在其中下载示例项目,并非常清楚地显示 Autofac 在此数学中的工作原理。

Autofac T

【讨论】:

  • 最终解决方案是上面的代码加上存储库和控制器构造函数的“InstancePerHttpRequest”,这是为了保证控制器和存储库的实例的唯一性(控制器因为它注入了一个存储库)。
猜你喜欢
  • 2017-06-12
  • 2012-09-05
  • 1970-01-01
  • 2021-03-17
  • 2011-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多