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

本文关键字:运行时 服务 Func 依赖 核心 NET 注入 使用 ASP | 更新日期: 2023-09-27 17:56:34

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

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

我有这2节课:

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 代码的新关键字。这是我发现的最好的方法,因为 Func 委托,我非常有限,我不能在接口中使用它,也不能覆盖它。

现在在启动中的配置服务方法中.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 是在我的基类中声明的关键字,而不是派生的关键字。

如果我这样做,它就可以工作

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

但我不想投射它,因为我不知道我的服务提供商最终会是哪种类型。

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

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

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

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

我在 Startup.cs 中的代码保持不变,但这是我的自定义服务提供商的新代码

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>>的类

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