ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c#-ILoggerFactory.GetCurrentClassLogger失败,仅在内部版本中出现InvalidOperationException

2019-10-27 16:05:02  阅读:343  来源: 互联网

标签:visual-studio-2015 dependency-injection net-4-5 c ninject-logging


上周,我的Windows Service应用程序到生产环境的部署失败,因此我尝试以发布模式在本地运行该项目,并收到InvalidOperationException:无法确定当前类.可以追溯到对GetCurrentClassLogger的调用.

我的项目使用Ninject将ILoggerFactory解析为中间层的每个服务.然后,该服务使用GetCurrentClassLogger()在构造函数中获取正确的ILogger.
例如:

public class FooService : IFooService
{
     private readonly ILogger logger;

     public FooService(ILoggerFactory loggerFactory)
     {
          this.logger = loggerFactory.GetCurrentClassLogger();
     }

     // ... 
}

如果我在Ninject.Extensions.Logging的LoggerFactoryBase上深入研究GetCurrentClassLogger的实现:

[MethodImpl(MethodImplOptions.NoInlining)]
public ILogger GetCurrentClassLogger()
{
  StackFrame stackFrame = new StackFrame(0, false);
  if (stackFrame.GetMethod() == (MethodBase) LoggerFactoryBase.getCurrentClassLoggerMethodInfo)
    stackFrame = new StackFrame(1, false);
  Type declaringType = stackFrame.GetMethod().DeclaringType;
  if (declaringType == (Type) null)
    throw new InvalidOperationException(string.Format("Can not determine current class. Method: {0}", (object) stackFrame.GetMethod()));
  return this.GetLogger(declaringType);
}

我可以看到在哪里引发了异常.

我的第一个直觉是检查是否由系统,框架或项目更新引起,但是自上次成功部署以来,没有做任何有意义的事情.

现在…关于此问题的“有趣”之处是,当我使用Trace.WriteLine(“ Test”);添加一行时;在构造函数中,GetCurrentClassLogger执行得很好.

我能够将此问题与编译器的代码优化联系起来.如果我在项目属性的“构建”选项卡中将其禁用,它也可以正常执行.

问题:什么会导致StackFrame停止提供DeclaringType?

同时,我将其用作解决方法,但我更喜欢使用原始方法:

this.logger = loggerFactory.GetLogger(this.GetType());

任何帮助将非常感激.

解决方法:

如果不看待CIL的发出,很难确切说明为什么行为不同,但是我猜想它已经内联了.
如果将构造函数的属性分配为:

[MethodImpl(MethodImplOptions.NoInlining)]

就像NInject代码正在做的一样.该方法可能内联,因为它只是分配了只读字段的一行.您可以在这里阅读一些有关内联如何影响StackFrames的信息:http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx

就是说,这种不可预测性是为什么使用堆栈框架是一个坏主意的原因.如果您希望不必指定类名的语法,而是使用VS 2012,并且文件名与类名匹配,则可以在扩展方法上使用CallerFilePath属性,并保留与现在相同的行为,而无需使用堆叠框架.看到:
https://msdn.microsoft.com/en-us/library/hh534540.aspx

更新:

一种替代方法是直接注入ILogger,并让您的容器负责确定要注入的组件的类型(因为它肯定知道).这似乎也更干净.从此处查看示例:https://github.com/ninject/ninject.extensions.logging/issues/19

    this.Bind<ILogger>().ToMethod(context =>
    {
        var typeForLogger = context.Request.Target != null
                                ? context.Request.Target.Member.DeclaringType
                                : context.Request.Service;
        return context.Kernel.Get<ILoggerFactory>().GetLogger(typeForLogger);
    });

标签:visual-studio-2015,dependency-injection,net-4-5,c,ninject-logging
来源: https://codeday.me/bug/20191027/1945767.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有