Используя модуль Autofac, вы можете подключиться к событиям Preparing
и Activating
:
Autofac регистрация:
builder.RegisterModule<TimeMeasuringResolveModule>();
TimeMeasuringResolveModule:
public class TimeMeasuringResolveModule : Module
{
private readonly ResolveInfo _current;
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += Registration_Preparing;
registration.Activating += Registration_Activating;
base.AttachToComponentRegistration(componentRegistry, registration);
}
private void Registration_Preparing(object sender, PreparingEventArgs e)
{
// Called before resolving type
_current = new ResolveInfo(e.Component.Activator.LimitType, _current);
}
private void Registration_Activating(object sender, ActivatingEventArgs<object> e)
{
// Called when type is constructed
var current = _current;
current.MarkComponentAsResolved();
_current = current.Parent;
if (current.Parent == null)
{
ResolveInfoVisualizer.VisualizeGraph(current);
}
}
}
ResolveInfo:
public sealed class ResolveInfo
{
private Stopwatch _watch = Stopwatch.StartNew();
public ResolveInfo(Type componentType, ResolveInfo parent)
{
ComponentType = componentType;
Parent = parent;
Dependencies = new List<ResolveInfo>(4);
if (parent != null) parent.Dependencies.Add(this);
}
public Type ComponentType { get; }
public List<ResolveInfo> Dependencies { get; }
// Time it took to create the type including its dependencies
public TimeSpan ResolveTime { get; private set; }
// Time it took to create the type excluding its dependencies
public TimeSpan CreationTime { get; private set; }
public ResolveInfo Parent { get; }
public void MarkComponentAsResolved()
{
ResolveTime = _watch.Elapsed;
CreationTime = ResolveTime;
foreach (var dependency in this.Dependencies)
{
CreationTime -= dependency.ResolveTime;
}
}
}
ResolveInfoVisualizer:
public static class ResolveInfoVisualizer
{
public static void VisualizeGraph(ResolveInfo node, int depth = 0)
{
Debug.WriteLine(
$"{new string(' ', depth * 3)}" +
$"{node.ComponentType.FullName} " +
$"({node.ResolveTime.TotalMilliseconds.ToString("F1")} ms. / " +
$"/ {node.CreationTime.TotalMilliseconds.ToString("F1")} ms.));
foreach (var dependency in node.Dependencies)
{
VisualizeGraph(dependency, depth + 1);
}
}
}
Вместо входа в окно отладки вы обычно должны использовать выходные данные в модульном тесте. Обратите внимание, что TimeMeasuringResolveModule
является НЕ поточно-ориентированным. Учитывая снижение производительности этого модуля, вы должны использовать его только как часть одного интеграционного теста.
Также обратите внимание, что хотя этот модуль генерирует графы объектов, он не выводит граф репрезентативных объектов, а состоит только из объектов, которые фактически активируются во время этого разрешения. Например, уже инициализированные синглтоны не будут отображаться на графике, так как они фактически не используются. Для визуализации достоверных графов объектов следует использовать другой метод.