首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >向动态加载的.dll (.net核心)注入依赖项

向动态加载的.dll (.net核心)注入依赖项
EN

Stack Overflow用户
提问于 2022-03-28 16:37:14
回答 2查看 1.3K关注 0票数 3

如何向动态加载的程序集注入依赖项类似,我希望从动态加载的程序集中将依赖项注入类。这在.NET 6.0DI容器中有可能吗?如果是这样的话,是怎么做的?如果没有,您可以推荐一个重量轻的IOC容器吗?(最好不要在项目中增加第二个国际奥委会系统。)(注意:只有2-4个最大可能的依赖项可以注入,所以一个带有if/switch语句的假注入系统是可以接受的。)

一个挑战是:ILogger<>通常需要一个类型,但是加载.dll对动态加载的程序集中的类型没有编译时知识,反之亦然。我可以使用非通用的ILogger接口,但不确定它是否适用于DI。

编辑:按要求展开示例:

给定的:所有要注入的潜在依赖项都来自Microsoft.Extensions.Hosting nuget包。我们最初希望使用的两个是ILogging<>和IConfiguration。

代码语言:javascript
运行
复制
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);
EN

回答 2

Stack Overflow用户

发布于 2022-04-21 19:50:52

我找到了一个非常丑陋的方法来完成这个任务,并且非常希望有一个更干净的方法来完成这个任务。(请有一种我错过的内置方式来做这件事。)

为GetInjectedObject提供程序创建扩展方法IService:

代码语言:javascript
运行
复制
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;
}

然后创建这样的对象:

代码语言:javascript
运行
复制
_classInstance = serviceProvider.GetInjectedObject(Class);
票数 3
EN

Stack Overflow用户

发布于 2022-04-22 08:40:52

也许我误解了这个问题,你是否可以:

  • 加载程序集(即成分根)和动态加载程序集是否共享程序集?此程序集可能包含动态加载类型必须实现的接口。(您可能已经有一个共享程序集)
  • 在启动时加载动态加载的程序集,此时您还在连接DI容器吗?

在这种情况下,我希望有一个类似于:

代码语言:javascript
运行
复制
namespace MySharedAssembly
{
    public interface ITask
    {
        void Execute(TaskSchedule schedule);
    }

    public class TaskSchedule { ... }
}

在动态加载的程序集中:

代码语言:javascript
运行
复制
namespace MyDynamicAssembly
{
    public class HelloWorldTask : ITask
    {
        public void Execute(TaskSchedule schedule)
        {
            Console.WriteLine("Hello world!");
        }
    }
}

通过这样做,你可以:

  • 通过ITask接口很容易地在动态加载的程序集中找到所有类型。
  • 根据它们的具体类型在DI容器中注册它们。
  • 在需要时通过它们的具体类型来解析它们,而依赖项则由DI容器注入。

例如:

代码语言:javascript
运行
复制
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);
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71650719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档