C#dependency injection运行时(动态)注册
我正在使用VS 2017和.NET Core。 使用dependency injection,我想在运行时动态注册我的服务。 我的目标是编写我的服务实例,在不同的程序集中实现服务接口。 然后将servicename /程序集名称添加到某种配置文件(或db表)中。
我的注册码会做这样的事情:
var ServiceTypeName = LoadServiceAssembly(AssemblyName); var serviceProvider = new ServiceCollection() .AddTransient() // <--- Goal .BuildServiceProvider(); var logger = serviceProvider.GetService(IDILogger);
显然,AddTransient行不起作用,因为这样的方法不存在。 然而,它确实描绘了这个想法。 我想通过字符串名称注册类型,以便每次添加新服务类型时都不需要重新编译加载器应用程序。
我似乎无法找到如何做到这一点。 欢迎大家提出意见。
TIA
您可以从设置中读取已配置的类型,通过reflection加载所需的类型并在服务集合中注册它:
// Read from config var assemblyPath = "..."; var typeName = "..."; var assembly = Assembly.LoadFrom(assemblyPath); var loggerType = assembly.GetType(typeName); var serviceProvider = new ServiceCollection() .AddTransient(typeof(IDILogger), loggerType) .BuildServiceProvider(); var logger = serviceProvider.GetService();
如果添加或重新配置新的记录器,这种动态方法将不需要任何重新编译。
这显然是不可能的,但是,我在项目中使用类似的东西,以避免必须将每个新类型添加到容器:
var assembly = typeof(YourClass).Assembly; // I actually use Assembly.LoadFile with well-known names var types = assembly.ExportedTypes // filter types that are unrelated .Where(x => x.IsClass && x.IsPublic); foreach (var type in types) { // assume that we want to inject any class that implements an interface // whose name is the type's name prefixed with I services.AddScoped(type.GetInterface($"I{type.Name}"), type); }
对于您的具体情况,您甚至可以缩短它:
var type = assembly.ExportedTypes.First(x => x.Name == runtimeName); services.AddScoped(typeof(IDILogger), type);
您可以使用工厂来实现这一目标。
services.AddScoped(provider => { //Resolve some service at runtime. var aService = provider.GetService(); //Any synchronous logic here return new MyDynamicService(); });