与如何向动态加载的程序集注入依赖项类似,我希望从动态加载的程序集中将依赖项注入类。这在.NET 6.0DI容器中有可能吗?如果是这样的话,是怎么做的?如果没有,您可以推荐一个重量轻的IOC容器吗?(最好不要在项目中增加第二个国际奥委会系统。)(注意:只有2-4个最大可能的依赖项可以注入,所以一个带有if/switch语句的假注入系统是可以接受的。)
一个挑战是:ILogger<>
通常需要一个类型,但是加载.dll对动态加载的程序集中的类型没有编译时知识,反之亦然。我可以使用非通用的ILogger
接口,但不确定它是否适用于DI。
编辑:按要求展开示例:
给定的:所有要注入的潜在依赖项都来自Microsoft.Extensions.Hosting nuget包。我们最初希望使用的两个是ILogging<>和IConfiguration。
Type desiredClass = <Type found in the dynamically loaded assembly>;
//The below line does not inject dependencies. I am trying to find out what will.
object classInstace = Activator.CreateInstance(desiredClass);
MethodInfo selectedMethod = desiredClass.GetMethods
.Single(m=>m.Name=="Execute" && m.GetParameters().All(p=>p.IsOptional));
//Schedule the method in HangFire
RecurringJob.AddOrUpdate(
() => selectedMethod!.Invoke(
ClassInstance,
Array.Empty<object?>(),
scheduleForThisTask);
发布于 2022-04-21 19:50:52
我找到了一个非常丑陋的方法来完成这个任务,并且非常希望有一个更干净的方法来完成这个任务。(请有一种我错过的内置方式来做这件事。)
为GetInjectedObject提供程序创建扩展方法IService:
public static object GetInjectedObject(this IServiceProvider serviceProvider, Type type)
{
//Dependency injection the ugly way
//Find the constructor that asks for the most injected parameters
var constructor = type.GetConstructors().Where(cn =>
cn.GetParameters().All(par => serviceProvider.GetServices(par.ParameterType).Any()))
.OrderByDescending(cn => cn.GetParameters().Length).FirstOrDefault();
if (null == constructor)
throw new Exception($"Type {type.Name} does not have a constructor without non-injectible parameters.");
//Get the needed parameters from the IServiceProvider
var constructorParameters =
constructor.GetParameters().Select(par => serviceProvider.GetService(par.ParameterType)).ToArray();
//Create the object with the parameters
var classInstance = Activator.CreateInstance(type, constructorParameters);
return classInstance;
}
然后创建这样的对象:
_classInstance = serviceProvider.GetInjectedObject(Class);
发布于 2022-04-22 08:40:52
也许我误解了这个问题,你是否可以:
在这种情况下,我希望有一个类似于:
namespace MySharedAssembly
{
public interface ITask
{
void Execute(TaskSchedule schedule);
}
public class TaskSchedule { ... }
}
在动态加载的程序集中:
namespace MyDynamicAssembly
{
public class HelloWorldTask : ITask
{
public void Execute(TaskSchedule schedule)
{
Console.WriteLine("Hello world!");
}
}
}
通过这样做,你可以:
ITask
接口很容易地在动态加载的程序集中找到所有类型。例如:
string dynamicallyLoadedAssemblyPath = "c:\\...\etc\etc\myAssembly.dll";
// Load plugin assembly
Assembly assembly =
Assembly.Load(AssemblyName.GetAssemblyName(dynamicallyLoadedAssemblyPath));
// Load plugin types
Type plugins = assembly.GetExportedTypes().Where(typeof(ITask).IsAssignableFrom);
// Register plugins in DI Container
foreach (var plugin in plugins)
{
services.AddTransient(plugin, plugin);
}
// Add jobs after container was constructed
IServiceProvider provider = ...
foreach (var plugin in plugins)
{
var scheduleForThisTask = GetSchedule(plugin);
RecurringJob.AddOrUpdate(() =>
{
// It might be important to execute each task in its own scope.
using (var scope = provider.CreateScope())
{
var task = (ITask)scope.ServiceProvider.GetRequiredService(plugin);
task.Execute(scheduleForThisTask);
}
}
}
https://stackoverflow.com/questions/71650719
复制相似问题