C# 如何解决.net内核中动态控制器的依赖关系?

C# 如何解决.net内核中动态控制器的依赖关系?,c#,C#,我正在为要从dll加载的类型动态创建控制器。为此,我创建了一个基本控制器来处理动态控制器请求 我的动态控制器在construcor中具有以下依赖项 公共类秩序 { 专用只读IDBLogger\u记录器; 私有只读IEExceptionHandler\u处理程序 公共秩序(IDBGLogger、IEExceptionHandler) { _记录器=记录器; _处理程序=处理程序 } public void GetOrderDetail() { _logger.log(“…”);//这里我得到的是空

我正在为要从dll加载的类型动态创建控制器。为此,我创建了一个基本控制器来处理动态控制器请求

我的动态控制器在construcor中具有以下依赖项

公共类秩序
{
专用只读IDBLogger\u记录器;
私有只读IEExceptionHandler\u处理程序
公共秩序(IDBGLogger、IEExceptionHandler)
{
_记录器=记录器;
_处理程序=处理程序
}
public void GetOrderDetail()
{
_logger.log(“…”);//这里我得到的是空引用,因为我无法解析此_记录器类型。
///rest代码
}
}

由于类是从dll加载的,我如何解决这个问题。

您可以使用反射动态加载依赖项和控制器。 有关更多信息,请访问以下链接。

我认为我对您的目标的假设与您的目标大相径庭,实际上,在我看来,您根本不需要与应用程序部件或功能提供商打交道。在我看来,这似乎是一个DI注册问题

  • 我从boilerplate.NETCore3.1MVC应用程序开始(没有什么特别之处)
  • 然后我又添加了两个类库项目:
    Common
    Orders
  • Common.dll 我假设您的接口(为了简洁起见,我将使用
    IDBLogger
    )必须对控制器程序集以及主应用程序可用。因此,这两个项目都将依赖它

    namespace Common
    {
        public interface IDBLogger
        {
            void Log(string s);
        }
    }
    
    Orders.dll 此程序集定义web api控制器:

    using Common;
    
    namespace Orders
    {
        public class Order
        {
            private readonly IDBLogger _logger;
            public Order(IDBLogger logger)
            {
                _logger = logger;
            }
            public void GetOrderDetail()
            {
                _logger.Log("Inside GetOrderDetail");
            }
        }
    }
    
    MVC 因为大部分代码都是标准的,所以我只列出我修改过的文件。 注意,现在我依赖于默认的控制器解析器,我只需要将我的类型注册到
    servicecolection

    Startup.cs ValuesController.cs
    [路由(“api/[控制器]”)]
    [ApiController]
    公共类值控制器
    {
    公共值控制器(IServiceProvider服务提供程序,已加载类型缓存)
    {
    var order=serviceProvider.GetService(cache.LoadedTypes[“order”]);//您可以在此处加载相同的程序集以再次获取类型,但我选择使用预加载的类型插入字典
    //下面两行代码只是为了调用该方法。您可能有更好的方法
    var m=cache.LoadedTypes[“order”].GetMethod(“GetOrderDetail”,BindingFlags.Public | BindingFlags.Instance);
    m、 调用(顺序,新对象[]{});
    }
    [HttpGet]
    公共IEnumerable Get()
    {
    返回新的[]{“value1”,“value2”};
    }
    }
    
    依靠内置的DI容器,我们不必考虑手动实例化动态加载的类型(以及它们的依赖项,只要DI容器知道它们)。您可能会发现,必须使用反射来处理这些实例有点麻烦,因此您可能希望在那里探索您的选项


    希望这是缺少的部分

    您是否介意分享更多关于如何从dll加载类型以及您当前在项目中使用的DI容器的详细信息?通过使用以下代码,我们可以从dll获取类型,并可以使用ApplicationFeatureProvider populateFeature()Assembly.LoadFrom将其添加到通用控制器(Path.Combine(assemblyFolder,“SampleOrder.dll”);我使用Activator.CreateInstance(type)为订单类型创建实例。但在order方法调用中,我使用了以下类型实例IDBLogger、IEExceptionHandler和getting null值,因为我无法在运行时解析这些依赖项。下一个问题:为什么要手动实例化控制器?我的理解是您和框架进行实例化(DI)对你来说..那么你的代码是什么呢
    Activator.CreateInstance(type)
    ?我从下面的线程中得到了一些添加通用控制器的想法。但唯一的区别是,在这个链接上,控制器类型ex:VanityOrderController代码在编译时可用,但对我来说,我从一些dll获得。因此,我们无法控制实例创建,所以我需要手动和动态地为我的“订单”创建类型。由于Order类型类具有构造函数依赖项参数,我无法解决该问题。希望您理解?有任何建议或想法吗?它没有再次解决该问题。我从Order类型的方法调用中获得空引用异常。依赖项未解决!感谢您的响应。这是最相似的代码,我的project有而不是ValuesController我有来自dll的Order类,它将被添加到控制器。我有basecontroller,它获取订单类类型api/Order,并在通过Activator.CreateInstance(orderType)创建实例之后我试图访问其方法,在该方法中,我获得了记录器类型的nullreference预期值。我修改了上面的代码以供您快速参考。虽然我们在sartup.cs文件中解析了记录器依赖项,但它无法从外部dll解析该类。
    ...
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews(); // add all controllers as you normally would. I think you don't need to mess with ApplicationParts. but if you do, you are already aware that https://stackoverflow.com/questions/36680933/discovering-generic-controllers-in-asp-net-core is a good example
    
        services.AddScoped<IDBLogger, IdbLogger>();
        // load assembly and register with DI
        var assembly = Assembly.LoadFrom(Path.Combine("..\\path\\to", "Orders.dll")); 
        var orderType = assembly.ExportedTypes.First(t => t.Name == "Order");
        services.AddScoped(orderType); // this is where we would make our type known to the DI container
    
        var loadedTypesCache = new LoadedTypesCache(); // this step is optional - I chose to leverage the same DI mechanism to avoid having to load assembly in my controller for type definition. you can probably find a better approach at doing this
        loadedTypesCache.LoadedTypes.Add("order", orderType);
        services.AddSingleton(loadedTypesCache); // singleton seems like a good fit here
    }
    
    using Common;
    using System;
    
    namespace Test
    {
        public class IdbLogger : IDBLogger
        {
            public void Log(string s)
            {
                Console.WriteLine(s); // nothing fancy here either
            }
        }
    }
    
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController
    {
        public ValuesController(IServiceProvider serviceProvider, LoadedTypesCache cache)
        {
            var order = serviceProvider.GetService(cache.LoadedTypes["order"]); // you could load the same assembly here to get the type again, but i opted to inject a dictionary with preloaded type instead
            
            // following two lines are just to call the method. you probably have better way of doing it
            var m = cache.LoadedTypes["order"].GetMethod("GetOrderDetail", BindingFlags.Public|BindingFlags.Instance);
            m.Invoke(order, new object[] { });
    
        }
    
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new [] { "value1", "value2" };
        }
    }