在WCF服务应用程序或WCF服务库中实现IErrorHandler

时间:2012-10-02 08:26:57

标签: c# wcf web-config

实现IErrorHandler接口并将其添加到WCF服务应用程序中的调度程序时,我遇到了一些奇怪的行为。 仅触发HandleError方法,而不是ProvideFault方法。

在WCF服务中使用相同的代码和配置时,两种方法都会在代码中的异常时触发。

示例:

public class ErrorHandler : IErrorHandler, IServiceBehavior
{
    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        // Provide the fault
    }

    public bool HandleError(Exception error)
    {
        // If handled return true, otherwise false
    }

    // Validate
    // AddBindingParameters
    // ApplyDispatchBehavior
}

public class ErrorHandlerBehavior : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(ErrorHandler); }
    }

    protected override object CreateBehavior()
    {
        return new ErrorHandler();
    }
}

在Web.config中:

    <extensions>
      <behaviorExtensions>
        <add name="ErrorLogging" type="Service.ErrorHandlerBehavior, Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
...
      <serviceBehaviors>
        <behavior>
          <ErrorLogging />
        </behavior>
      </serviceBehaviors>

代码和配置是相同的(尽管配置在Service Application中的Web.config和服务库中的i App.config中)。

ProvideFaultHandleError中插入断点我可以看到ProvideFault仅针对服务调用 - 这怎么可能?我错过了什么吗?

修改

当被调用的服务操作的签名具有除基本类型之外的返回类型时,似乎不调用ProvideFault,例如:

public IEnumerable<MyType> GetMyType(string s1)
{
    throw new Exception("Testing...");
}

...不会触发ProvideFault

可是:

public bool DoStuff(string s1, string s2)
{
    throw new Exception("Testing...");
}

...会触发ProvideFault

1 个答案:

答案 0 :(得分:0)

NicklasJepsen,你接近正确的答案。 我刚刚遇到与IEnumerable相同的问题,但设法解决它,而不是改变返回类型。

在我的情况下,问题的原因是该方法使用了yield return语句。您可能知道,返回IEnumerable并使用yield return返回元素的方法被编译为“状态机”。实际上它返回IEnumerable实例,它返回迭代器,这些方法实现了该状态机。这个伟大的功能在于LINQ的核心,它允许延迟执行 - 只有当你需要另一个元素时,状态机才能工作。

在WCF的情况下,我想我知道会发生什么。 WCF的行为有点像这样:

  1. 它调用方法。

  2. 如果方法失败,WCF会将异常传递给您的ErrorHandler方法(两者都有)。

  3. 如果方法成功,WCF将准备响应。它按照响应格式序列化方法返回的对象。

  4. 如果序列化失败(预期比方法失败更少),WCF会将异常传递给ErrorHandler,但仅传递给方法HandleError。出于某种原因,现阶段不会调用ProvideFault。

  5. 如果序列化成功,序列化对象将被发送到客户端。

  6. 现在考虑以下两个例子:

    public bool DoStuff();
    public IEnumerable<bool> DoALotOfStuff();
    

    DoStuff肯定在第2步失败了。但是DoALotOfStuff没有!请记住,它是一个状态机,执行被推迟到查询第一个元素的那一刻。因此,该方法不会失败,它只返回IEnumerable实例,一旦您需要元素,它就可以为您提供枚举器。 因此,WCF对方法返回的内容感到满意,因此它继续进行序列化。这就是你的阴险异常!

    现在,解决方案非常简单 - 只是不要推迟执行。返回一个“真实的”可枚举实例,如List而不是“状态机”。

    public IEnumerable<bool> DoALotOfStuff()
    {
        return _DoALotOfStuff().ToList();
    }
    
    protected IEnumerable<bool> _DoALotOfStuff()
    {
        yield return true;
        yield return false;
        throw new Exception( "Testing..." );
    }
    

    现在,如果方法失败,它会在正确的位置失败,因此您调用了ProvideFault。