[英]Injecting dependencies into dynamically loaded .dll (.net core)
類似於How to Inject Dependencies to Dynamically Loaded Assemblies ,我想將依賴項注入到動態加載程序集中的類中。 使用 .NET 6.0 DI 容器是否可行? 如果是這樣,如何? 如果沒有,您是否可以推薦一個輕量級的 IOC 容器? (最好不要向項目添加第二個 IOC 系統。)(注意:最多只能注入 2-4 個依賴項,因此可以接受帶有 if/switch 語句的假注入系統。)
一個挑戰: ILogger<>
通常需要一個類型,但 loading.dll 沒有動態加載程序集中類型的編譯時知識,反之亦然。 我可以使用非通用ILogger
接口,但不確定它是否適用於 DI。
編輯:根據要求擴展示例:
給定:要注入的所有潛在依賴項都來自 Microsoft.Extensions.Hosting nuget package。我們最初希望使用的兩個是 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);
我找到了一種非常丑陋的方法來完成這項工作,並且非常希望有一種更簡潔的方法來完成這項工作。 (請讓我錯過了一個內置的方法來做到這一點。)
為 IService Provider 創建一個擴展方法 GetInjectedObject:
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);
也許我誤解了這個問題,它對你有用嗎:
在那種情況下,我希望界面類似於:
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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.