ASP.NET 核心依赖注入:使用 Func 委托在运行时解析服务

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

我正在尝试向我的控制器注入服务,但我想根据几个参数注入我的服务的不同实例。实际上对于这部分它正在工作,我能够做到。

我想要的是根据我们从配置文件中获得的一些配置加载 IRepository<Database> 的特定实例并遵守 DRY 规则(不要重复自己)。

我有这 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;
    };
}

注意用于重新定义我的 Func 代码的 new 关键字。这是我找到的最好的方法,因为 Func 委托,我非常有限,我不能在接口中使用它,也不能覆盖它。

现在在我的 ConfigureServices 方法中 Startup.cs 我有这个代码

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);

我的问题是 new 关键字在运行时被忽略,执行的 Func 是在我的基 class 中声明的,而不是派生的。

如果我这样做就可以了

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

但我不想转换它,因为我不知道我的 servicesProvider 最终会是哪种类型。

我试图获取我的 servicesProvider 的类型并将其转换为自己的类型,但我收到编译器错误,因为 Type 变量和 Class 是不同。

那么如何让好的Func在运行时执行呢?谢谢

好的,所以我终于设法做了我想做的事,实际上并没有那么难,我的主要问题是处理这样一个事实,即我的 Func 不是方法而是代表。我不习惯处理这种变量类型。

我在 Startup.cs 中的代码保持不变,但这是我的自定义 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;
    }        
}

以防万一人们想知道:DatabaseFileSystemRepository 是实现接口 IRepository<Database>>

的 class

如果有人提出不同的解决方案,我非常想知道。