实现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中)。
在ProvideFault
和HandleError
中插入断点我可以看到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
。
答案 0 :(得分:0)
NicklasJepsen,你接近正确的答案。 我刚刚遇到与IEnumerable相同的问题,但设法解决它,而不是改变返回类型。
在我的情况下,问题的原因是该方法使用了yield return语句。您可能知道,返回IEnumerable并使用yield return返回元素的方法被编译为“状态机”。实际上它返回IEnumerable实例,它返回迭代器,这些方法实现了该状态机。这个伟大的功能在于LINQ的核心,它允许延迟执行 - 只有当你需要另一个元素时,状态机才能工作。
在WCF的情况下,我想我知道会发生什么。 WCF的行为有点像这样:
它调用方法。
如果方法失败,WCF会将异常传递给您的ErrorHandler方法(两者都有)。
如果方法成功,WCF将准备响应。它按照响应格式序列化方法返回的对象。
如果序列化失败(预期比方法失败更少),WCF会将异常传递给ErrorHandler,但仅传递给方法HandleError。出于某种原因,现阶段不会调用ProvideFault。
如果序列化成功,序列化对象将被发送到客户端。
现在考虑以下两个例子:
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。