Я долгое время пользовался 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-фреймворков в итоге будет работать прекрасно.