I was a long time user of Autofac that recently switched to Simple Injector for my DI container needs. When I used Autofac, I was able to do something I'm still not able to do with Simple Injector, maybe because I do not yet perfectly understand the API.
Let's say I have the service IEntityRepository
of TEntity
and TDbContext
. It's implementation looks like that:
public class EntityRepository<TEntity, TDbContext> : IEntityRepository<TEntity, TDbContext>
where TDbContext : IEntityDbContext where TEntity : class
{
public EntityRepository(TDbContext dbContext)
{
}
}
With Autofac, I was able to register the open generic implementation EntityRepository
as the open generic interface IEntityRepository
, so when I would inject say, IEntityRepository
of Product
and IProductsDbContext
, the DI container would automatically guess that I inject through the constructor an instance of ProductsDbContext
.
Is this possible with Simple Injector? I tries these, but it still fails:
container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>).Assembly);
container.Register(typeof(IEntityRepository<,>), typeof(EntityRepository<,>));
Thanks in advance for you help!
EDIT: So here's a full exemple with Autofac as requested by Steven. Create a new .NET Core Console Application. You'll need to install the NuGet Package 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);
}
The final console output should ressemble to:
Database context is of type GenericTypeDiTester.DbContexts.ProductsDbContext. Resolved IEntityRepository is of type: GenericTypeDiTester.Repositories.EntityRepository`2[GenericTypeDiTester.Models.Product,GenericTypeDiTester.Interfaces.DbContexts.IProductsDbContext]
You can download the full example there: https://drive.google.com/file/d/1UkIYxLsY6YGwo5jOB5TyyncXc6yho8X5/view?usp=sharing
EDIT 2: The problem wasn't with the Simple Injector library at the end. It seems that mixing the usage of Microsoft.DependencyInjection and SimpleInjector isn't really a good thing. As suggested by Steven, you should exclusively use SI to register the majority of your services and in rare case, MS.DI (by example for using AddDbContext).
As for my part, I have in my project MediatR, a library that implements the Mediator pattern. This library offers a NuGet package with an extension method AddMediatR for the IServiceCollection of MS.DI, which is supposed to register all handlers properly, but it wasn't the case for me. So I ended up registering the module all by myself using SI.
At the end it everything worked perfectly. You really need to call these lines at the end of the registering process: EnableSimpleInjectorCrossWiring
and UseSimpleInjectorAspNetRequestScoping
. Nothing else must be registered using the IServiceCollection afterwards. That way, the cross wiring of both DI framework ends up to work beautifully.
IProductsDbContext
toProductsDbContext
) that is currently missing from your Simple Injector configuration. It might be useful to share an MCVE that shows a working example of your Autofac configuration. - Steven