如何调试Unity分辨率?

时间:2016-03-31 11:36:03

标签: c# wpf dependency-injection unity-container prism

在WPF项目中(使用prism),我们使用Unity作为DI框架。

最近,在我们合并了两个大分支后,我们无法启动我们的应用程序,我们有StackOverflowException。由于异常的性质,我们无法获得他的调用堆栈或当前值,我们只是因为命名空间而导致问题是来自Unity。

我们花了5个多小时才找到问题所在:

简化为:

我们有3-4个服务(A,B,C和D),每个服务都有一个实现,在某些时候,服务A需要服务B,这需要服务C,这是需要的服务D,需要服务A)。基本上是循环参考。

我们想知道是否有可能添加Unity尝试使用实现X解决服务A的一些日志,并且需要解析服务B,......

这可以帮助我们调试这个问题,直接查看这个循环引用中涉及哪些服务。

无论如何要实现这个目标吗?

3 个答案:

答案 0 :(得分:4)

聚会晚了一点,但是对于完全相同的问题,我创建了这个,并且工作正常:

internal class LogExtension : UnityContainerExtension
{
    public LogExtension( ILogger logger )
    {
        _logger = logger;
    }

    #region UnityContainerExtension
    protected override void Initialize()
    {
        Context.Strategies.Add( new LoggingStrategy( _logger ), UnityBuildStage.PreCreation );
    }
    #endregion

    #region private
    private readonly ILogger _logger;

    private class LoggingStrategy : BuilderStrategy
    {
        public LoggingStrategy( ILogger logger )
        {
            _logger = logger;
        }

        #region BuilderStrategy
        public override void PreBuildUp( IBuilderContext context )
        {
            _logger.Log( $"Resolving {context.BuildKey.Type} for {context.OriginalBuildKey.Type}" );
        }
        #endregion

        #region private
        private readonly ILogger _logger;
        #endregion
    }
    #endregion
}

在引导程序中的某个位置(很可能是ConfigureContainer):

Container.AddExtension( new LogExtension( _logger ) );

答案 1 :(得分:0)

您可以配置程序集绑定日志查看器Fusion Log,以帮助诊断有问题的Unity解析。

它与Visual Studio一起安装,您只需在VS命令提示符下键入“fuslogvw”即可启动。

否则,这可能有助于配置记录器:How do I enable assembly bind failure logging (Fusion) in .NET?

答案 2 :(得分:0)

如果你用的是Unity v5+,懒得查v4到v5有什么变化,那你可以复制我的版本:

using System.Reflection;
using Unity.Extension;
using Unity.Builder;
using Unity.Strategies;

namespace Company.ProjectName.Shared.Bootstrap.Unity
{
    public class LogResolvesUnityContainerExtension : UnityContainerExtension
    {
        private static readonly ILogger Logger = LoggerManager.CreateLogger(MethodBase.GetCurrentMethod().DeclaringType);
        
        protected override void Initialize()
        {
            Context.Strategies.Add(new LoggingStrategy(Logger), UnityBuildStage.PreCreation);
        }

        private class LoggingStrategy : BuilderStrategy
        {
            private readonly ILogger _logger;
            
            public LoggingStrategy(ILogger logger)
            {
                _logger = logger;
            }

            public override void PreBuildUp(ref BuilderContext context)
            {
                // Be aware that for Singleton Resolving this log message will only be logged once, when the Singleton is first resolved. After that, there is no buildup and it is just returned from a cache.
                
                var registrationType = context.RegistrationType; 
                var registrationName = context.Name;
                var resolvedType = context.Type;
                
                var registrationNameWithParenthesesOrNothing = string.IsNullOrEmpty(registrationName) ? "" : $"({registrationName})";
                _logger.LogDebug($"Resolving [{registrationType}{registrationNameWithParenthesesOrNothing}] => [{resolvedType}]");
            }
        }
    }
}

感谢 Haukinger 编写了 v4 原始版本。