首页 > 解决方案 > Autofac - IRegistrationSource 未应用

问题描述

由于我需要控制注入的实例,我尝试关注这篇文章:https ://autofac.readthedocs.io/en/latest/advanced/registration-sources.html

这是我的实现:

public class ModuleAutofacRegistrationSource : IRegistrationSource
{
    public bool IsAdapterForIndividualComponents => false;

    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)
    {
        var swt = service as IServiceWithType;
        if (swt == null || !typeof(Foundation.Core.Modules.Framework.IModule).IsAssignableFrom(swt.ServiceType))
        {
            // It's not a request for the base handler type, so skip it.
            return Enumerable.Empty<IComponentRegistration>();
        }

        var registration = new ComponentRegistration(
                                    Guid.NewGuid(),
#pragma warning disable CS8602 // Dereference of a possibly null reference.
                                    new DelegateActivator(swt.ServiceType, (c, p) =>
#pragma warning restore CS8602 // Dereference of a possibly null reference.
                                    {
#pragma warning disable CS8603 // Possible null reference return.
                                        return ModuleRegistry.Instance.GetModule(swt.ServiceType);
#pragma warning restore CS8603 // Possible null reference return.
                                    }),
                                    new CurrentScopeLifetime(),
                                    InstanceSharing.Shared,
                                    InstanceOwnership.OwnedByLifetimeScope,
                                    new[] { service },
                                    new Dictionary<string, object>());

        return new IComponentRegistration[] { registration };
    }
}

所以代替示例中的工厂,我只是返回 ModuleRegistry.Instance.GetModule(swt.ServiceType);

我的注册是这样完成的:

builder.RegisterSource(new ModuleAutofacRegistrationSource());
builder.RegisterAssemblyTypes(dlwAssemblies)
                .Where(x => x.IsClass && !x.IsAbstract && typeof(IModule).IsAssignableFrom(x))
                .AsImplementedInterfaces()
                .SingleInstance();

当我调试时,我看到我的 RegistrationSource 被调用,直到我第二次返回,但他从未调用我的 DelegateActivator,当然还有 GetModule 方法。我感觉autofac可以用另一种方式解决它,所以他不需要调用我的方法。在我的消费者类中,我有一个 IModule 的“空”实例,我的意思是一个没有通过 GetModule 方法注入的值的类。

问候,

编辑:

这是跟踪器的结果

Resolve Operation Starting
{
  Resolve Request Starting
  {
    Service: Dlw.Kentico.Foundation.Core.Modules.Feature.DynamicResponsiveImage.Services.IResponsiveImageService
    Component: Dlw.Kentico.Foundation.Core.Modules.Feature.DynamicResponsiveImage.Services.ResponsiveImageService

    Pipeline:
    -> CircularDependencyDetectorMiddleware
      -> ScopeSelectionMiddleware
        -> SharingMiddleware
          -> RegistrationPipelineInvokeMiddleware
            -> ActivatorErrorHandlingMiddleware
              -> DisposalTrackingMiddleware
                -> ResponsiveImageService (ReflectionActivator)
                  Resolve Request Starting
                  {
                    Service: Dlw.Kentico.Foundation.Core.Modules.Feature.FocusImageEditor.Repositories.IFocusImageEditorRepository
                    Component: Dlw.Kentico.Foundation.Core.Modules.Feature.FocusImageEditor.Repositories.FocusImageEditorRepository

                    Pipeline:
                    -> CircularDependencyDetectorMiddleware
                      -> ScopeSelectionMiddleware
                        -> SharingMiddleware
                          -> RegistrationPipelineInvokeMiddleware
                            -> ActivatorErrorHandlingMiddleware
                              -> DisposalTrackingMiddleware
                                -> FocusImageEditorRepository (ReflectionActivator)
                                <- FocusImageEditorRepository (ReflectionActivator)
                              <- DisposalTrackingMiddleware
                            <- ActivatorErrorHandlingMiddleware
                          <- RegistrationPipelineInvokeMiddleware
                        <- SharingMiddleware
                      <- ScopeSelectionMiddleware
                    <- CircularDependencyDetectorMiddleware
                  }
                  Resolve Request Succeeded; result instance was Dlw.Kentico.Foundation.Core.Modules.Feature.FocusImageEditor.Repositories.FocusImageEditorRepository
                  Resolve Request Starting
                  {
                    Service: CMS.DocumentEngine.IAttachmentInfoProvider
                    Component: λ:CMS.DocumentEngine.IAttachmentInfoProvider

                    Pipeline:
                    -> CircularDependencyDetectorMiddleware
                      -> ScopeSelectionMiddleware
                        -> SharingMiddleware
                        <- SharingMiddleware
                      <- ScopeSelectionMiddleware
                    <- CircularDependencyDetectorMiddleware
                  }
                  Resolve Request Succeeded; result instance was CMS.DocumentEngine.AttachmentInfoProvider
                  Resolve Request Starting
                  {
                    Service: Dlw.Kentico.Foundation.Core.Logging.IDlwLogger
                    Component: Dlw.Kentico.Frontend.Modules.Foundations.Logging.DlwLogger

                    Pipeline:
                    -> CircularDependencyDetectorMiddleware
                      -> ScopeSelectionMiddleware
                        -> SharingMiddleware
                        <- SharingMiddleware
                      <- ScopeSelectionMiddleware
                    <- CircularDependencyDetectorMiddleware
                  }
                  Resolve Request Succeeded; result instance was Dlw.Kentico.Frontend.Modules.Foundations.Logging.DlwLogger
                  Resolve Request Starting
                  {
                    Service: Dlw.Kentico.Foundation.Core.Modules.Feature.ResponsiveImage.IResponsiveImageModule
                    Component: Dlw.Kentico.Frontend.Modules.Features.ResponsiveImage.ResponsiveImageModule

                    Pipeline:
                    -> CircularDependencyDetectorMiddleware
                      -> ScopeSelectionMiddleware
                        -> SharingMiddleware
                          -> RegistrationPipelineInvokeMiddleware
                            -> ActivatorErrorHandlingMiddleware
                              -> DisposalTrackingMiddleware
                                -> ResponsiveImageModule (ReflectionActivator)
                                <- ResponsiveImageModule (ReflectionActivator)
                              <- DisposalTrackingMiddleware
                            <- ActivatorErrorHandlingMiddleware
                          <- RegistrationPipelineInvokeMiddleware
                        <- SharingMiddleware
                      <- ScopeSelectionMiddleware
                    <- CircularDependencyDetectorMiddleware
                  }
                  Resolve Request Succeeded; result instance was Dlw.Kentico.Frontend.Modules.Features.ResponsiveImage.ResponsiveImageModule
                <- ResponsiveImageService (ReflectionActivator)
              <- DisposalTrackingMiddleware
            <- ActivatorErrorHandlingMiddleware
          <- RegistrationPipelineInvokeMiddleware
        <- SharingMiddleware
      <- ScopeSelectionMiddleware
    <- CircularDependencyDetectorMiddleware
  }
  Resolve Request Succeeded; result instance was Dlw.Kentico.Foundation.Core.Modules.Feature.DynamicResponsiveImage.Services.ResponsiveImageService
}
Operation Succeeded; result instance was Dlw.Kentico.Foundation.Core.Modules.Feature.DynamicResponsiveImage.Services.ResponsiveImageService

编辑 2:有关我需要实现的目标的更多信息:

  1. 我的班级IResponsiveImageModule继承自IFeatureModule谁继承IModule
  2. public void ConfigureServices(IServiceCollection services)我创建这些模块的实例(因此是 的实例ResponsiveImageModule)期间,我根据设置设置了此模块的一些属性。
  3. 当注入IResponsiveImageModule我的班级时ResponsiveImageService,我想接收我在步骤 2 中初始化的对象的实例

标签: c#autofacasp.net-core-3.1

解决方案


您正在注册一个源,但也注册了程序集类型。最后查询源 - 显式注册始终优先。如果您正在解析您正在注册的任何程序集类型,这就是它不调用该激活器的原因。

如果您尝试诊断支持,有时会更容易发现此类情况。

如果您确定这不是正在发生的事情,也许可以深入研究问题以解释通过程序集类型调用注册和注册的内容以及您认为源应该处理的内容。这里没有足够的信息来跟踪整个事情。


根据问题的变化进行更新:

即使有跟踪器输出,这里也不足以解决这个问题。我建议用尽可能少的移动部件制作一个最小的、可重现的设置示例,以缩小问题范围。

当前问题中省略了很多重要的东西,表面上是由于复杂性,这实际上是理解整个设置和帮助所必需的。例如:

  • 您正在注册dlwAssemblies,但我们不知道这些程序集是什么或其中的类型。
  • 您期望某些东西(我们不知道是什么)来解决某种“模块”(我们不知道是什么),并且该模块......预计来自源头?或不?这并不完全清楚。

这有点像一个 400 块拼图,只有 200 块拼在一起,你问我是否认为这里的这一部分是正确的……但我们看不到原始图片或拼图的其余部分件。

在创建您的最小示例时,它可以帮助您调试自己的问题。这实际上对进行最小复制的努力是一个巨大的好处——通过消除额外的复杂性,不仅让回答问题的人更容易看到发生了什么,而且还让你,问问题的人清楚事情.

在制作该复制品时,我建议简化为:

  • 不包括程序集注册。只需注册一种您希望通过 注册的类型RegisterAssemblyTypes。(如果事情开始起作用,这表明您可能应该检查那里注册的内容。)
  • 不要打电话module- 它会与 Autofac 模块混淆,至少对于试图回答的人来说。
  • 如果您发布代码,请删除#pragma评论,额外的非必需品更难阅读。
  • 不要有一堆你期望来自你的注册源的东西,只要有一个. 这样您就知道它要么通过您的注册源,要么正在发生其他事情。
  • 像单元测试一样编写它。您可以控制一切的一种方法 - 容器的设置,类型的分辨率。不要通过应用程序请求或其他任何方式运行它。如果它开始工作,你就知道是一些额外的东西导致了问题;如果它不起作用,那么您将无法专注于修复。

我还强烈建议通读示踪剂结果。这不仅适合我们,也适合您。如果它没有意义,请开始进行一些搜索,深入研究它。您正在创建注册源,这是您可以使用 Autofac 完成的更复杂的事情之一。如果您无法阅读跟踪器结果,则可能表明您需要退后一步并了解更多 Autofac 内部是如何工作的,这也可能意味着查看 Github 中的代码。是的,这真的很深。如果你想做困难的事情,有时你必须潜入水中。

我自己阅读跟踪器输出,我看到:

  • 您正在解决一个IResponsiveImageServiceResponsiveImageService. 这正在通过反射解决- ResponsiveImageService (ReflectionActivator)
  • 四个依赖ResponsiveImageService项(如果您进行最小的复制,这是更容易遵循的事情之一)。
    • IFocusImageEditorRepository(由 实现FocusImageEditorRepository)通过反射解决-FocusImageEditorRepository (ReflectionActivator)
    • IAttachmentInfoProvider(由返回对象的 lambda 实现 - 因此λ:CMS.DocumentEngine.IAttachmentInfoProvider)似乎已经被解析并正在共享,就像它是一个单例或“每个生命周期范围内的实例”之类的东西。我们看到这一点是因为它从SharingMiddleware.
    • IDlwLogger(由 实现DlwLogger)也是单例或以某种方式共享,也来自SharingMiddleware.
    • IResponsiveImageModule(由 实现ResponsiveImageModule)通过反射激活-ResponsiveImageModule (ReflectionActivator)

因此,鉴于所有这些,似乎ResponsiveImageModule是通过该RegisterAssemblyTypes调用找到的。

这是有道理的,因为您的注册...

builder.RegisterAssemblyTypes(dlwAssemblies)
  .Where(x => x.IsClass && !x.IsAbstract && typeof(IModule).IsAssignableFrom(x))
  .AsImplementedInterfaces()
  .SingleInstance();

...基本上就是这样做的-它正在注册,以进行反射,任何可以转换为IModule. 而且,就像我之前说的,注册源是最后查询的,所以如果你希望模块来自你的注册源,那么你可能需要一个!在某个地方,这样它就不会注册你的模块。(不过,老实说,您仍然不清楚您在这里真正想要完成什么,以及什么是或没有按预期工作。)

我希望这有助于解除对您的阻止。如果有的话,也许它给了你一些看地方的想法。不幸的是,我可以分配给问题和支持的时间有限,并且我需要将其传播开来,因此即使您最终确定了最小的复制,我也不会回来进行第三次迭代。这里的提示和说明必须足够,至少来自我,我很抱歉是这样的。祝你好运;我觉得你真的很亲近。


推荐阅读