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
如果有人提出不同的解决方案,我非常想知道。
我正在尝试向我的控制器注入服务,但我想根据几个参数注入我的服务的不同实例。实际上对于这部分它正在工作,我能够做到。
我想要的是根据我们从配置文件中获得的一些配置加载 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>>
如果有人提出不同的解决方案,我非常想知道。