简体   繁体   中英

ASP.NET Core dependency injection: Service resolved at runtime using a Func delegate

I'm trying to inject a service to my controllers but I want to inject a different instance of my service depending of several parameters. Actually for this part it's working, I'm able to do it.

What I want is to load a specific instance of IRepository<Database> based on some configuration we get from a configuration file and respecting the DRY rule (don't repeat yourself).

I have these 2 classes:

public abstract class FooServicesProvider
{
    public Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider =>
    {
        return null;
    };
}

public class FooFileSystemServicesProvider : FooServicesProvider
{
    public new Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider =>
    {
        //Specific code determining which database to use and create a new one if needed
        //our databases are FOLDERS containing some files
        //knowing how chosenDb.FullName is set is not important here
        //[...]
        var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName);
        databaseRepository.testProperty = "Foo value";
        return databaseRepository;
    };
}

Notice the new keyword used to redefine the code of my Func. This is the best way I found because of the Func delegate, I'm very limited, I can't use it in an Interface neither override it.

Now in my ConfigureServices method in Startup.cs I have this code

var fakeConfiguration = "File";
FooServicesProvider servicesProvider = null;
if(fakeConfiguration == "File")
{
    servicesProvider = new FooFileSystemServicesProvider();
}
else
{
    servicesProvider = new AnotherFooServicesProvider();
}
//Here is the tricky part
//This should call FooFileSystemServicesProvider.DatabaseRepository because of the "new" keyword, but it's NOT
services.AddScoped<IRepository<Database>>(servicesProvider.DatabaseRepository);

My problem is that the new keyword is ignored at runtime and the executed Func is the one declared in my base class instead of the derived one.

If I do this it's working

services.AddScoped<IRepository<Database>>((servicesProvider as FooFileSystemServicesProvider).DatabaseRepository);

But I don't want to cast it as I can't know of which type my servicesProvider will finally be.

I've tried to get the type of my servicesProvider and cast it with its own type but I get compiler error because a Type variable and a Class are different.

So how can I get the good Func executed at runtime? Thanks

Ok so I finally managed to do what I want, it was actually not that hard, my main problem was to handle the fact that my Func was not a method but a delegate. I'm not used to deal with this variable type.

My code in Startup.cs remains unchanged but here is the new code of my custom ServicesProvider

public abstract class FooServicesProvider
{
    public Func<IServiceProvider, IRepository<Database>> DatabaseRepository { get; protected set; } 
}

public class FooFileSystemServicesProvider : FooServicesProvider
{
    public FooFileSystemServicesProvider()
    {
        base.DatabaseRepository = GetDatabaseRepository;
    }

    private DatabaseFileSystemRepository GetDatabaseRepository(IServiceProvider serviceProvider)
    {
        //Specific code determining which database to use and create a new one if needed
        //our databases are FOLDERS containing some files
        //knowing how chosenDb.FullName is set is not important here
        //[...]
        var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName);
        databaseRepository.testProperty = "Foo value";
        return databaseRepository;
    }        
}

Just in case people are wondering: DatabaseFileSystemRepository is a class that implements the interface IRepository<Database>>

If anyone comes up with a different solution, I'm very curious to know it.

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