框架服务注册|使用反射时找不到注册类| AppDomain问题



我正在ASP上实现c#框架。. NET使用dotnet6。我希望框架的一部分可以被外部各方扩展;他们只需要实现几个类,我们可以通过Nuget或直接汇编引用来集成他们的工作。

他们需要完成的部分工作是一个注册类,这样他们就可以定义他们的引擎应该如何在依赖注入容器中注册。这是我期望第三方提供的一个例子:
public class EchoServiceRegistration : IRegisterDI
{
  public IServiceCollection Register(IServiceCollection serviceCollection)
  {
    serviceCollection.TryAddSingleton<EchoEngine>();
    return serviceCollection;
  }
}

在消费应用程序中,我正在寻找使用AppDomain类实现IRegisterDI接口的所有类,这是对这个SO答案https://stackoverflow.com/a/26750/2573109的模仿。(注意:我切换到使用基于名称的匹配只是为了排除故障,一旦正确解决,将更改回更好的实现):

List<Type> allRegistrationClasses = AppDomain
  .CurrentDomain
  .GetAssemblies()
  .SelectMany(it => it.GetTypes())
  .Where(tp => tp.GetInterfaces()
    .Any(inter => inter.Name == nameof(IRegisterDI)))
  .ToList();

如上所述,返回0个类型。

在下一个故障排除迭代中,我证明了注册类对调用者是可用的。因此,我手动创建了EchoServiceRegistration类的一个实例,如下所示。这一次,AppDomain包含echoservicereregistration的单个条目(如预期的那样)。

var allRegistrationClasses = AppDomain.CurrentDomain.GetAssemblies().SelectMany(it => it.GetTypes()).Where(tp => tp.GetInterfaces().Any(inter => inter.Name == nameof(IRegisterDI))).ToList();
var echoServiceRegistration = new EchoServiceRegistration();
echoServiceRegistration.Register(builder.Services);
if (allRegistrationClasses.Count is not 1) throw new InvalidOperationException(); // Does not throw an exception

为了证明我没有不小心修复了什么,我注释掉了与Echo服务注册相关的两行,并且allRegistrationClasses再次包含0条记录。

var allRegistrationClasses = AppDomain.CurrentDomain.GetAssemblies().SelectMany(it => it.GetTypes()).Where(tp => tp.GetInterfaces().Any(inter => inter.Name == nameof(IRegisterDI))).ToList();
// var echoServiceRegistration = new EchoServiceRegistration();
// echoServiceRegistration.Register(builder.Services);
if (allRegistrationClasses.Count is not 1) throw new InvalidOperationException(); // Throws an exception

我的直觉反应是我不明白AppDomain如何决定加载什么程序集。我开始阅读微软提供的关于它的文档,但这似乎是一个深奥的话题,如果没有相当多的专门阅读,我不会有更清晰的理解。

我如何保证在DI容器构建期间调用该类时可用的全部类集?如果我能提供任何额外的细节或清晰度,请告诉我。

在我看来,在你的第一个测试中,程序集没有加载到应用程序域中,因为它没有被使用。

在第二个测试中,您正在手动创建实例,因此您正在强制加载程序集。请注意,即使将程序集作为引用添加,也不会加载它,除非它确实需要。

您需要显式加载要扫描的程序集。这样做的一种方法是将所有扩展库都放在一个特定的文件夹中,然后您可以在注册之前加载它们:

var files = Directory.GetFiles(@"C:my-frameworkextensions");
foreach (var file in files)
{
    var extension = Path.GetExtension(file);
    if(extension == ".dll")
    {
        var asm = Assembly.LoadFile(file);
        Console.WriteLine($"Loaded extension [{asm.FullName}]");
    }
}

一旦程序集被加载,你应该得到想要的结果。

这是一个过于简单的例子,但它应该足以让你了解。

相关内容

最新更新