【问题标题】:Why does Type.GetInterfaces() sometimes not return a valid list?为什么 Type.GetInterfaces() 有时不返回有效列表?
【发布时间】:2012-09-21 22:33:21
【问题描述】:

我们继承了我们想要改进的设计不佳的 WCF 服务。它的一个问题是它有一百多个方法(在两个不同的接口上),我们怀疑其中大部分没有使用。我们决定对每个方法进行一些日志记录,以跟踪它们何时以及如何被调用。为了使跟踪代码易于重构和防错字,我们这样实现它:

public void LogUsage()
{
    try
    {
        MethodBase callingMethod = new StackTrace().GetFrame(1).GetMethod();
        string interfaceName = callingMethod.DeclaringType.GetInterfaces()[0].Name;
        _loggingDao.LogUsage(interfaceName, callingMethod.Name, GetClientAddress(), GetCallingUrl());
    }
    catch (Exception exception)
    {
        _legacyLogger.Error("Error in usage tracking", exception);
    }
}

LogUsage() 然后在我们要跟踪的每个方法的开头调用。

该服务的流量非常高,每天大约有 500,000 多个呼叫。 99.95% 的时间里,这段代码执行得很漂亮。但另外 0.05% 的时间,GetInterfaces() 返回一个空(但不是null)数组。

为什么GetInterfaces() 偶尔会返回不一致的结果?

这似乎微不足道 - 0.05% 的错误率是我们通常只能梦想的事情。但关键是要识别所有服务接触点,如果这个错误总是来自一个(或几个)方法调用,那么我们的跟踪是不完整的。我尝试通过调用服务上的每个方法在我的开发环境中重现此错误,但无济于事。

【问题讨论】:

  • 由于某处不正确地重新抛出异常而导致堆栈跟踪不完整?
  • 如果你也记录callingMethod,你可能会发现它的声明类型实际上没有接口。
  • LogUsage 只能从两个类中的方法调用,并且这两个类都实现了至少一个接口。

标签: c# wcf reflection


【解决方案1】:

StackTrace 是出了名的不可靠,尤其是在多线程环境中。或者更确切地说,它非常可靠,但有时不是很实用。询问“最后调用的方法”可能会产生意想不到的结果。尝试记录 DeclaringType。你可能会对在那里发现的东西感到惊讶。请注意,虽然现在这是 0.05% 的故障率,但它可能会随着应用程序的复杂性而增加。

为了正确实现可重用的跟踪代码,您需要依赖 .NET 4.5 功能 Caller Information、使用动态代理(例如 Castle Dynamic Proxy)或使用 AOP 框架(例如 @987654323) @。或者,您可以手动编写跟踪代码。

【讨论】:

  • "StackFrame 不是线程安全的"是我考虑过的一种可能性;但是,the MSDN documentation 说“StackTrace 是使用调用者的当前线程创建的”,所以我想我可以依赖它。很高兴知道。 (仅供参考,出于政治原因,我暂时无法对服务进行任何更改,因此目前无法选择加强日志记录 [叹气])
【解决方案2】:

来自 Erik Lippert(在 MS 的 C# 编译器团队工作)回复 Getting Type T from a StackFrame

堆栈帧实际上并没有告诉你是谁调用了你的方法。这 堆栈帧告诉您控制将返回到哪里。堆栈 框架是延续的具体化。事实上,谁打电话给 方法和控制返回的位置几乎总是相同的 事情是你困惑的根源,但我向你保证,他们需要 不一样。

整篇文章值得一读……

【讨论】:

    猜你喜欢
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 2021-03-23
    相关资源
    最近更新 更多