简单注入器-在运行时基于指定的泛型类型注入服务

时间:2019-03-03 20:34:55

标签: c# .net-core asp.net-core-mvc simple-injector

我是Autofac的长期用户,最近为我的DI容器需求切换到Simple Injector。当我使用Autofac时,我能够使用Simple Injector仍然无法执行某些操作,这可能是因为我尚未完全理解API。

假设我有IEntityRepositoryTEntity的服务TDbContext。它的实现如下所示:

    public class EntityRepository<TEntity, TDbContext> : IEntityRepository<TEntity, TDbContext>
            where TDbContext : IEntityDbContext where TEntity : class
        {
            public EntityRepository(TDbContext dbContext)
            {
            }
        }

使用Autofac,我能够将开放式通用实现EntityRepository注册为开放式通用接口IEntityRepository,因此当我注入IEntityRepository中的Product时, IProductsDbContext,DI容器会自动猜测我通过构造函数注入了ProductsDbContext的实例。

使用简单进样器可以做到吗?我尝试了这些,但仍然失败:

container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>).Assembly);
container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>));

预先感谢您的帮助!

编辑: 因此,这是史蒂文要求的Autofac的完整示例。创建一个新的.NET Core控制台应用程序。您需要安装NuGet软件包Autofac。

Program.cs:

internal class Program
    {
        private static void Main(string[] args)
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<ProductsDbContext>().AsImplementedInterfaces();
            builder.RegisterGeneric(typeof(EntityRepository<,>)).As(typeof(IEntityRepository<,>));

            var container = builder.Build();
            using (var scope = container.BeginLifetimeScope())
            {
                var productsRepository = scope.Resolve<IEntityRepository<Product, IProductsDbContext>>();
                Console.WriteLine($"Resolved IEntityRepository is of type: {productsRepository.GetType()}");
            }
        }
    }

ProductsDbContext.cs

public class ProductsDbContext : IProductsDbContext
    {
        public void Dispose()
        {
            // Demo, do nothing.
        }

        public int SaveChanges()
        {
            throw new System.NotImplementedException();
        }
    }

Product.cs

public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

EntityRepository.cs

public class EntityRepository<TEntity, TDbContext> : IEntityRepository<TEntity, TDbContext>
        where TDbContext : IEntityDbContext where TEntity : class
    {
        private readonly TDbContext _dbContext;

        public EntityRepository(TDbContext dbContext)
        {
            _dbContext = dbContext;
            Console.WriteLine($"Database context is of type {dbContext.GetType()}.");
        }

        public IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> whereClause)
        {
            throw new NotImplementedException();
        }
    }

IEntityDbContext.cs

public interface IEntityDbContext : IDisposable
    {
        int SaveChanges();
    }

IProductsDbContext.cs

public interface IProductsDbContext : IEntityDbContext
    {

    }

IEntityRepository.cs

public interface IEntityRepository<TEntity, TDbContext> where TDbContext : IEntityDbContext where TEntity : class
    {
        IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> whereClause);
    }

最终的控制台输出应类似于:

  

数据库上下文是类型   GenericTypeDiTester.DbContexts.ProductsDbContext。解决   IEntityRepository的类型为:   GenericTypeDiTester.Repositories.EntityRepository`2 [GenericTypeDiTester.Models.Product,GenericTypeDiTester.Interfaces.DbContexts.IProductsDbContext]

您可以在此处下载完整的示例:https://drive.google.com/file/d/1UkIYxLsY6YGwo5jOB5TyyncXc6yho8X5/view?usp=sharing

编辑2: 最后,问题与简单注入器库无关。似乎将Microsoft.DependencyInjection和SimpleInjector的用法混合在一起并不是一件好事。正如Steven所建议的那样,您应专门使用SI来注册大多数服务,而在极少数情况下,应使用MS.DI(例如,使用AddDbContext的方式)进行注册。

就我而言,我在我的项目MediatR中有一个实现Mediator模式的库。该库为MS.DI的IServiceCollection提供了一个具有扩展方法AddMediatR的NuGet程序包,该程序应正确注册所有处理程序,但对我而言并非如此。因此,我最终自己使用SI注册了该模块。

最后,一切正常。您确实需要在注册过程结束时调用以下行:EnableSimpleInjectorCrossWiringUseSimpleInjectorAspNetRequestScoping。之后,无需使用IServiceCollection进行注册。这样,两个DI框架的交叉布线最终都能正常工作。

1 个答案:

答案 0 :(得分:3)

在Simple Injector中进行注册的方法是:

container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>));
container.Register<IProductsDbContext, ProductsDbContext>();

尽管有几种方法可以实现相同的目标,但Simple Injector中没有AsImplementedInterfaces等效项。如果ProductsDbContext有多个需要注册的接口,最明显的方法是显式注册每个接口:

container.Register<IProductsDbContext, ProductsDbContext>();
container.Register<IUsersDbContext, ProductsDbContext>();
container.Register<ICustomersDbContext, ProductsDbContext>();
相关问题