[英]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). 我想要的是根据我们从配置文件获得的某些配置并遵守DRY规则(不重复自己),加载
IRepository<Database>
的特定实例。
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. 请注意用于重新定义我的Func代码的new关键字。 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.
这是我发现的最好方法,因为有Func委托,我非常有限,不能在接口中使用它,也不能覆盖它。
Now in my ConfigureServices method in Startup.cs I have this code 现在在Startup.cs的 ConfigureServices方法中,我有以下代码
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. 我的问题是new关键字在运行时被忽略,执行的Func是在我的基类中声明的关键字,而不是派生的关键字。
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. 但是我不想进行转换,因为我不知道我的servicesProvider最终将是哪种类型。
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. 我试图获取我的servicesProvider的类型并将其强制转换为其自己的类型,但是由于Type变量和Class不同,我遇到了编译器错误。
So how can I get the good Func executed at runtime? 那么,如何在运行时执行良好的Func? 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. 好的,所以我终于设法做自己想做的事,实际上并不难,我的主要问题是要处理我的Func不是方法而是委托的事实。 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 我在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;
}
}
Just in case people are wondering: DatabaseFileSystemRepository
is a class that implements the interface IRepository<Database>>
以防万一,人们想知道:
DatabaseFileSystemRepository
是一个实现IRepository<Database>>
接口的类。
If anyone comes up with a different solution, I'm very curious to know it. 如果有人提出不同的解决方案,我很好奇。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.