1

在实现 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和Service Library的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.

4

1 回答 1

0

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

就我而言,问题原因是该方法使用了 yield return 语句。您可能知道,返回 IEnumerable 并使用 yield return 返回元素的方法被编译为“状态机”。实际上,它返回 IEnumerable 实例,该实例返回迭代器,哪些方法实现了该状态机。这个伟大的特性在于 LINQ 的核心,它允许延迟执行——状态机仅在您需要另一个元素时工作。

如果是 WCF,我想我知道会发生什么。WCF 的行为有点像这样:

  1. 它调用方法。

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

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

  4. 如果序列化失败(比方法失败更不期望),WCF 会将异常传递给您的 ErrorHandler,但仅传递给方法 HandleError。由于某种原因,在此阶段未调用 ProvideFault。

  5. 如果序列化成功,则将序列化的对象发送给客户端。

现在考虑这两个例子:

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。

于 2013-02-26T06:26:09.527 回答