在 autofac 中可视化依赖树深度
Visualizing dependency tree depth in autofac
我可能一直在搜索错误的东西,在错误的框中查找。但是我似乎找不到一种好方法来可视化我的依赖树在 C# 中的深度。
我最初只是尝试连接 Autofac 的准备事件和激活事件。但我不知道这是否足够好。结果看起来有点古怪。似乎准备事件启动得太频繁了。而且激活事件似乎只有在实际创建新对象时才会激活。
我们的代码是.NET 4.7.2
我们使用 Autofac 作为我们的容器来处理依赖注入。
有没有人知道我们如何可视化深度?也许有一些好的代码或产品可以帮助我们?
前段时间,我在Autofac上有过类似的任务。我最终得到的结果如下:
public class DebugResolveModule : Module
{
private readonly ThreadLocal<ResolveInfo> _current = new ThreadLocal<ResolveInfo>();
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)
{
_current.Value = new ResolveInfo(e.Component.Activator.LimitType, _current.Value);
}
private void Registration_Activating(object sender, ActivatingEventArgs<object> e)
{
var current = _current.Value;
current.MarkComponentAsResolved();
_current.Value = current.Parent;
if (current.Parent == null)
{
VisualizeGraph(current);
Debug.WriteLine(
$"total resolve time: {current.ResolveTime.TotalMilliseconds} ms.");
}
}
private static void VisualizeGraph(ResolveInfo node, int depth = 0)
{
for (int i = 0; i < depth; i++)
{
Debug.Write(" ");
}
Debug.Write(node.ComponentType);
Debug.Write(" (");
Debug.Write(node.ResolveTime.TotalMilliseconds.ToString("F1"));
Debug.Write(" ms. / ");
Debug.Write(node.CreationTime.TotalMilliseconds.ToString("F1"));
Debug.Write(" ms.)");
Debug.WriteLine("");
foreach (var dependency in node.Dependencies)
{
VisualizeGraph(dependency, depth + 1);
}
}
private 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; }
// 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 List<ResolveInfo> Dependencies { get; }
public void MarkComponentAsResolved()
{
ResolveTime = _watch.Elapsed;
CreationTime = ResolveTime;
foreach (var dependency in this.Dependencies)
{
CreationTime -= dependency.ResolveTime;
}
_watch = null;
}
}
}
请注意,这并不是您想要的,因为它是一个解决触发器。这意味着 SingleInstance
仅解析一次,这意味着您下次请求图形时,您将丢失单例。这对我来说不是问题,因为我使用这段代码来检测对象图的缓慢解析部分。
但是,此代码可能仍会为您提供有关如何执行此操作的一些想法。
我可能一直在搜索错误的东西,在错误的框中查找。但是我似乎找不到一种好方法来可视化我的依赖树在 C# 中的深度。
我最初只是尝试连接 Autofac 的准备事件和激活事件。但我不知道这是否足够好。结果看起来有点古怪。似乎准备事件启动得太频繁了。而且激活事件似乎只有在实际创建新对象时才会激活。
我们的代码是.NET 4.7.2 我们使用 Autofac 作为我们的容器来处理依赖注入。
有没有人知道我们如何可视化深度?也许有一些好的代码或产品可以帮助我们?
前段时间,我在Autofac上有过类似的任务。我最终得到的结果如下:
public class DebugResolveModule : Module
{
private readonly ThreadLocal<ResolveInfo> _current = new ThreadLocal<ResolveInfo>();
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)
{
_current.Value = new ResolveInfo(e.Component.Activator.LimitType, _current.Value);
}
private void Registration_Activating(object sender, ActivatingEventArgs<object> e)
{
var current = _current.Value;
current.MarkComponentAsResolved();
_current.Value = current.Parent;
if (current.Parent == null)
{
VisualizeGraph(current);
Debug.WriteLine(
$"total resolve time: {current.ResolveTime.TotalMilliseconds} ms.");
}
}
private static void VisualizeGraph(ResolveInfo node, int depth = 0)
{
for (int i = 0; i < depth; i++)
{
Debug.Write(" ");
}
Debug.Write(node.ComponentType);
Debug.Write(" (");
Debug.Write(node.ResolveTime.TotalMilliseconds.ToString("F1"));
Debug.Write(" ms. / ");
Debug.Write(node.CreationTime.TotalMilliseconds.ToString("F1"));
Debug.Write(" ms.)");
Debug.WriteLine("");
foreach (var dependency in node.Dependencies)
{
VisualizeGraph(dependency, depth + 1);
}
}
private 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; }
// 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 List<ResolveInfo> Dependencies { get; }
public void MarkComponentAsResolved()
{
ResolveTime = _watch.Elapsed;
CreationTime = ResolveTime;
foreach (var dependency in this.Dependencies)
{
CreationTime -= dependency.ResolveTime;
}
_watch = null;
}
}
}
请注意,这并不是您想要的,因为它是一个解决触发器。这意味着 SingleInstance
仅解析一次,这意味着您下次请求图形时,您将丢失单例。这对我来说不是问题,因为我使用这段代码来检测对象图的缓慢解析部分。
但是,此代码可能仍会为您提供有关如何执行此操作的一些想法。