26

我正在尝试调试遗留代码库中的一些问题。我认为是由抛出异常引起的,因为 Autofac 容器无法解决某些问题。但是我认为异常被埋在某个地方,我没有看到根本原因。我确信控制器正在请求一些无法找到的东西,或者可以找到的东西具有无法满足的依赖关系。没有任何保护条款等,所以我认为我遇到了一个空引用问题。为了尝试调试它,我想查看在容器中找不到的所有请求。

无论如何要记录 Autofac 无法解决的所有请求?或者只是将所有请求记录到容器中?

4

3 回答 3

40

您可以通过注册一个特殊模块来为容器的请求添加日志记录,该模块将捕获Preparing所有注册的事件:

public class LogRequestsModule : Module
{
  protected override void AttachToComponentRegistration(
    IComponentRegistry componentRegistry,
    IComponentRegistration registration)
  {
    // Use the event args to log detailed info
    registration.Preparing += (sender, args) =>
      Console.WriteLine(
        "Resolving concrete type {0}",
        args.Component.Activator.LimitType);
  }
}

这是最简单的方法,可能会得到你想要的。在Preparing事件记录信息后,您会立即看到异常弹出,并且您会知道哪个组件正在抛出。

如果你想变得更高级,你可以在容器ChildLifetimeScopeBeginning、、、和事件上设置一些事件处理程序。ResolveOperationBeginningResolveOperationEndingCurrentScopeEnding

  • 在此期间ChildLifetimeScopeBeginning,您需要设置一些东西以自动附加到任何子生命周期ResolveOperationBeginning事件。
  • ResolveOperationBeginning您记录将要解决的问题期间。
  • ResolveOperationEnding您记录出现的任何异常期间。
  • 在此期间CurrentScopeEnding,您需要取消订阅该范围内的任何事件,以便垃圾收集器可以使用其所有实例清理生命周期范围。

Whitebox profiler 项目有一个模块,它实现了一些更高级的日志记录,但它没有为最新的 Autofac 设置,所以你必须使用它作为起点,而不是剪切/粘贴示例。

同样,最简单的解决方案是我在上面发布的那个模块。

于 2013-09-03T19:57:16.873 回答
32

只是建立在 Travis 的出色答案的基础上,以防将来对某人有所帮助。

如果您的类结构非常深,如果您在组合层次结构中显示对象,则可能更容易发现有问题的路径。这可以通过这样的方式来完成:

using System;
using System.Text;
using Autofac;
using Autofac.Core;

namespace Tests
{
    public class LogRequestModule : Module
    {
        public int depth = 0;

        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
                                                              IComponentRegistration registration)
        {
            registration.Preparing += RegistrationOnPreparing;
            registration.Activating += RegistrationOnActivating;
            base.AttachToComponentRegistration(componentRegistry, registration);
        }

        private string GetPrefix()
        {
            return new string('-',  depth * 2);
        }

        private void RegistrationOnPreparing(object sender, PreparingEventArgs preparingEventArgs)
        {
            Console.WriteLine("{0}Resolving  {1}", GetPrefix(), preparingEventArgs.Component.Activator.LimitType);
            depth++;
        }

        private void RegistrationOnActivating(object sender, ActivatingEventArgs<object> activatingEventArgs)
        {
            depth--;    
            Console.WriteLine("{0}Activating {1}", GetPrefix(), activatingEventArgs.Component.Activator.LimitType);
        }
    }
}

样本输出:

--Resolving  SomeProject.Web.Integration.RestApiAdapter.RestApiAdapter
----Resolving  SomeProject.Web.Integration.RestApiAdapter.Client.ClientFactory
------Resolving  SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
------Activating SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
------Resolving  SomeProject.Web.Integration.RestApiAdapter.Client.Authentication.ApiClientAuthenticationService
--------Resolving  SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
--------Activating SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
------Activating SomeProject.Web.Integration.RestApiAdapter.Client.Authentication.ApiClientAuthenticationService
于 2014-04-30T16:27:38.630 回答
5

这个问题的其他答案适用于版本 5.x的 Autofac 。任何为Autofac 版本 6.x寻找答案的人都应该查看对 Diagnostics & Logging 的内置支持。Autofac 不再需要自定义逻辑来实现此问题中请求的日志记录类型。

其中的相关部分是:

  • 您不再需要将其集成到您的注册级别逻辑中。尽管您可以根据需要,但在链接的 URL 中有一个示例
  • 使用 aDefaultDiagnosticTracer来协调您的诊断。这是 Autofac 的一流部分。您设置它,然后让您的容器订阅它。

这是一个简单的示例,它仅用于Console.WriteLine记录诊断内容。您应该用您希望为您的应用程序使用的任何日志记录机制替换它。

var tracer = new DefaultDiagnosticTracer();
tracer.OperationCompleted += (sender, args) =>
{
    Console.WriteLine(args.TraceContent);
};
container.SubscribeToDiagnostics(tracer);
于 2021-02-09T12:44:53.290 回答