简体   繁体   中英

Register both generic and specific implementation of an interface with ASP.NET Core DI

I've read the Armen Shimoon's article ASP.NET Core: Factory Pattern Dependency Injection and I've decided to solve my ASP.NET Core DI problem using the technique suggested by him. I've got a generic interface:

public interface IItemRepository<out T> where T : BaseItem

and its generic implementation:

public class ItemRepository<T> : IItemRepository<T> where T : BaseItem

I register it with:

services.AddSingleton(typeof(IItemRepository<>), typeof(ItemRepository<>));

But for Currency I've got a specific implementation:

public class CurrencyRepository : ItemRepository<Currency>

(Curency is of the BaseItem type.) What I want is to register

CurrencyRepository

for

IItemRepository<Currency>

and

ItemRepository<T>

for all other items that implement BaseItem . I created a factory class to accomplish this:

public class ItemRepositoryFactory : IServiceFactory> where T : BaseItem
{
    private readonly ApplicationDbContext _context;

    public ItemRepositoryFactory(ApplicationDbContext context)
    {
        _context = context;
    }

    public ItemRepository Build()
    {
        if (typeof(T) == typeof(Currency))
            return new CurrencyRepository(_context) as ItemRepository;

        return new ItemRepository(_context);
    }
}

but I don't know how to register it with IServiceCollection . Or maybe I'm not on the right way at all?

You can't register it explicitly. ASP.NET Core DI is meant to be simple and offer out of box DI/IoC experience and easy for other DI/IoC containers to plugin.

So the built-in IoC doesn't offer Auto-Registrations, Assembly scanning, Decorators or registration of all interfaces/sub types of the class.

For concrete implementations, there is a "workaround"

services.AddScoped<IMyService,MyService>();
services.AddScoped<MyService>(provider => provider.GetService<IMyService>());

Then both MyService and IMyService inside a constructor would receive the same instance of the class.

But this doesn't work with open generics and is a manuell process. For automatic discovery or registration you need a 3rd party IoC container, such as Autofac, StructureMap etc.

But in your concrete sample it should be enough to register IItemRepository<Currency> inside your ConfigureServices method

services.AddScoped<IItemRepository<Currency>,CurrencyRepository>();

But actually the open generic should cover this case already, if you inject IItemRepository<Currency> into your services.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM