【问题标题】:Calling Abort on faulted WCF channel causes server side error to be logged在有故障的 WCF 通道上调用 Abort 会导致记录服务器端错误
【发布时间】:2010-12-08 12:56:06
【问题描述】:

当从我的 WCF 服务返回 FaultException 时,我需要中止通道而不是关闭它。我的客户端和服务都可以使用这种方法正常工作,但是在服务上实现 IErrorHandler 并记录任何异常之后,我可以看到在客户端上调用 Abort 会导致服务记录:

System.ServiceModel.CommunicationException:套接字连接被中止...

我不想用这些信息污染我的服务日志,只想记录与服务相关的错误。我知道我显然可以停止记录任何 CommunicationExceptions,但我的服务也是其他服务的 WCF 客户端,并且应该记录这些服务引发的 CommunicationExceptions。

我怎样才能阻止它这样做?

【问题讨论】:

  • 你能解释一下为什么你会中止而不是关闭吗?它可能会帮助您获得更好的答案。
  • WCF 有一个众所周知的问题,即在发生异常后在通道上调用 Close() 会引发异常本身,从而掩盖原始异常。因此,一旦通道发生故障,您将使用 Abort() 而不是 Close()。请参阅下面 Tomas 的链接以及他在博客文章中引用的链接。

标签: wcf logging error-handling ierrorhandler


【解决方案1】:

由于没有其他人回答过这个问题(托马斯的回答不相关),我问了一些该领域的专家。不幸的是,没有很好的方法来阻止这种情况,他们能想出的最好方法是在 IErrorHandler 中添加逻辑,以不记录以“套接字连接已中止”开头的消息的 CommunicationExcepions。不是很优雅,但它确实有效。

【讨论】:

    【解决方案2】:

    问题是,如果您在调用 dispose 时遇到异常,您将获得一个涵盖您的基础异常的异常,这是可能的。我写了一个包装器来处理这样的场景,你可以在我的博客上阅读它:http://blog.tomasjansson.com/2010/12/disposible-wcf-client-wrapper/

    这个想法是,如果 dispose 方法抛出异常,您的通道周围会有一个包装器来处理该场景。

    你应该如何使用我的包装器的一个小例子:

    public class ClientWrapperUsage : IYourInternalInterface
    {
        public IList<SomeEntity> GetEntitiesForUser(int userId)
        {
            using(var clientWrapper = new ServiceClientWrapper<ServiceType>())
            {
                var response = clientWrapper.Channel.GetEntitiesForUser();
                var entities = response.YourListOfEntities.TranslateToInternal();
                return entities;
            }
        }
    }
    

    这里我假设它存在一个列表的扩展方法,该方法包含服务返回的实体,然后您使用该方法将其转换为内部实体。这是 100% 可测试的,至少我认为 :)。只需在您不想伪造服务的任何地方修改界面IYourInternalInterface

    【讨论】:

    • 这不是问题。该代码完美运行并生成正确的客户端异常。问题在于 SERVICE 记录了一个额外的错误,指出客户端已中止通道。在我的代理中,我有与您的代码类似的代码,它调用 Abort 而不是 Close on exceptions,正是这段代码实际上导致了服务上的额外日志。除非您在服务上实现 IErrorHandler,否则您甚至不会看到这个问题,但事实上,它正在污染我的服务错误日志,并且难以阅读任何实际错误。
    • 顺便说一句,您博客中的方法存在一个问题,即使用您的 ServiceClientWrapper 的任何代码都不可单元测试。您可能想看看这种方法 - favcode.net/browse/… - 恕我直言,它非常有效。代码有点复杂,因为它使用的是 Castle Dynamic Proxy,但将代理视为普通类的优点使其非常值得。我确实尝试将其放在您的博客上,但被标记为垃圾邮件!
    • 执行中止时是否出现异常?或者你什么时候得到异常?您是否使用包装器,使用您拥有的代码更新您的问题....这样可以更容易回答问题。
    • 首先记录原始(服务生成)异常,然后客户端中止通道,然后记录第二个不需要的异常。
    • 为什么这个单元不可测试?此外,在使用时测试那段代码更像是集成测试而不是单元测试。您应该这样做的方法是定义一个您想从服务中获取的接口,然后让实现该接口的类使用包装器。这样你就隐藏了你正在使用 Web 服务的事实,这是一件好事。我会用一个小例子来更新答案。
    猜你喜欢
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 2016-08-05
    • 2011-03-04
    • 2010-12-06
    • 2011-07-16
    相关资源
    最近更新 更多