我正在尝试调试遗留代码库中的一些问题。我认为是由抛出异常引起的,因为 Autofac 容器无法解决某些问题。但是我认为异常被埋在某个地方,我没有看到根本原因。我确信控制器正在请求一些无法找到的东西,或者可以找到的东西具有无法满足的依赖关系。没有任何保护条款等,所以我认为我遇到了一个空引用问题。为了尝试调试它,我想查看在容器中找不到的所有请求。
无论如何要记录 Autofac 无法解决的所有请求?或者只是将所有请求记录到容器中?
我正在尝试调试遗留代码库中的一些问题。我认为是由抛出异常引起的,因为 Autofac 容器无法解决某些问题。但是我认为异常被埋在某个地方,我没有看到根本原因。我确信控制器正在请求一些无法找到的东西,或者可以找到的东西具有无法满足的依赖关系。没有任何保护条款等,所以我认为我遇到了一个空引用问题。为了尝试调试它,我想查看在容器中找不到的所有请求。
无论如何要记录 Autofac 无法解决的所有请求?或者只是将所有请求记录到容器中?
您可以通过注册一个特殊模块来为容器的请求添加日志记录,该模块将捕获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
、、、和事件上设置一些事件处理程序。ResolveOperationBeginning
ResolveOperationEnding
CurrentScopeEnding
ChildLifetimeScopeBeginning
,您需要设置一些东西以自动附加到任何子生命周期ResolveOperationBeginning
事件。ResolveOperationBeginning
您记录将要解决的问题期间。ResolveOperationEnding
您记录出现的任何异常期间。CurrentScopeEnding
,您需要取消订阅该范围内的任何事件,以便垃圾收集器可以使用其所有实例清理生命周期范围。Whitebox profiler 项目有一个模块,它实现了一些更高级的日志记录,但它没有为最新的 Autofac 设置,所以你必须使用它作为起点,而不是剪切/粘贴示例。
同样,最简单的解决方案是我在上面发布的那个模块。
只是建立在 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
这个问题的其他答案适用于版本 5.x的 Autofac 。任何为Autofac 版本 6.x寻找答案的人都应该查看对 Diagnostics & Logging 的内置支持。Autofac 不再需要自定义逻辑来实现此问题中请求的日志记录类型。
其中的相关部分是:
DefaultDiagnosticTracer
来协调您的诊断。这是 Autofac 的一流部分。您设置它,然后让您的容器订阅它。这是一个简单的示例,它仅用于Console.WriteLine
记录诊断内容。您应该用您希望为您的应用程序使用的任何日志记录机制替换它。
var tracer = new DefaultDiagnosticTracer();
tracer.OperationCompleted += (sender, args) =>
{
Console.WriteLine(args.TraceContent);
};
container.SubscribeToDiagnostics(tracer);