Простой инжектор - сервис инъекции на основе указанного универсального типа во время выполнения - PullRequest
0 голосов
/ 03 марта 2019

Я долгое время пользовался Autofac, который недавно переключился на Simple Injector для своих нужд в DI-контейнере.Когда я использовал Autofac, я смог сделать что-то, что я до сих пор не смог сделать с помощью Simple Injector, возможно, потому, что я еще не совсем понимаю API.

Допустим, у меня есть сервис IEntityRepository из TEntity и 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]

1049
1052 https://drive.google.com/file/d/1UkIYxLsY6YGwo5jOB5TyyncXc6yho8X5/view?usp=sharing
1050*

РЕДАКТИРОВАТЬ 2: Проблема не была с библиотекой Simple Injector в конце.Кажется, что смешивать использование Microsoft.DependencyInjection и SimpleInjector не очень хорошая вещь.По предложению Стивена, вы должны использовать исключительно SI для регистрации большинства своих сервисов, а в редких случаях MS.DI (например, для использования AddDbContext).

Что касается меня, то в моем проекте MediatR есть библиотека, которая реализует шаблон Mediator.Эта библиотека предлагает пакет NuGet с методом расширения AddMediatR для IServiceCollection MS.DI, который должен правильно регистрировать все обработчики, но для меня это было не так.В итоге я сам зарегистрировал модуль, используя SI.

В конце все заработало отлично.Вам действительно нужно вызвать эти строки в конце процесса регистрации: EnableSimpleInjectorCrossWiring и UseSimpleInjectorAspNetRequestScoping.После этого больше ничего не должно быть зарегистрировано с использованием IServiceCollection.Таким образом, перекрестная разводка обеих DI-фреймворков в итоге будет работать прекрасно.

1 Ответ

0 голосов
/ 04 марта 2019

Способ регистрации этого в Простом Инжекторе:

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

В Простом Инжекторе нет эквивалента AsImplementedInterfaces, хотя есть несколько способов добиться того же самого.В случае, если ProductsDbContext имеет несколько интерфейсов, которые необходимо зарегистрировать, наиболее очевидный способ - зарегистрировать каждый интерфейс явно:

container.Register<IProductsDbContext, ProductsDbContext>();
container.Register<IUsersDbContext, ProductsDbContext>();
container.Register<ICustomersDbContext, ProductsDbContext>();
...