捕获从IErrorHandler抛出的泛型FaultException <t>?</t>

时间:2014-01-24 21:44:47

标签: wcf web-services

对于服务,所有操作都可以抛出一组错误,因此为了集中这些错误,我创建了一个行为FaultAdderBehavior,它将错误契约添加到服务的所有操作中。它似乎工作正常,因为合同被添加到WSDL中,客户端可以通过以下行来捕获错误:

...
catch(FaultException<MyFault> e){ ... }
...

我还制作了一个IErrorHandler,它将非故障异常转换为某种故障。见下文。 问题是,错误处理程序中构造的错误无法在客户端上捕获。也就是说,它不能作为泛型 FaultException<MyFault>捕获,而只能作为FaultException捕获。 如果我向操作显式添加FaultContract(typeof(MyFault)),客户端可以突然捕获通用错误异常。

所以这可能表明我的FaultAdderBehavior出了问题。或者我的错误处理程序有问题吗?

我注意到,作为fault.Action的参数给出的CreateMessage()为空。这引起了我的关注。

以下是说明问题的示例。方法ShouldThrowFault()导致头痛,而ThrowsDirectly()完全符合要求。

总结一下,我的问题是:为什么客户端在来自错误处理程序时无法捕获泛型FaultException<MyFault>

[ServiceContract]
public interface IUncatchableFaultService
{
  [OperationContract]
//    [FaultContract(typeof(MyFault))]
  void ShouldThrowFault(string arg1);  

  [OperationContract]
  void ThrowsDirectly();
}

[FaultAdderBehavior(typeof(MyFault), typeof(MyFault2))]
[MyErrorHandlerBehavior]
internal class UncatchableFaultService : IUncatchableFaultService
{
  public void ShouldThrowFault(string arg1)
  {
    throw new Exception();
  }

  public void ThrowsDirectly()
  {
    throw new FaultException<MyFault>(new MyFault());
  }
}

[DataContract]
public class MyFault
{
}

[DataContract]
public class MyFault2
{
}

public class MyErrorHandlerBehaviorAttribute : Attribute, IServiceBehavior
{
  public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
  {
  }

  public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
  {
  }

  public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
  {
    foreach (ChannelDispatcherBase dispatcherBase in serviceHostBase.ChannelDispatchers)
    {
      ChannelDispatcher channelDispatcher = dispatcherBase as ChannelDispatcher;
      if (channelDispatcher == null) continue;
      channelDispatcher.ErrorHandlers.Add(new MyErrorHandler());
    }
  }

  private class MyErrorHandler : IErrorHandler
  {

    public void ProvideFault(Exception error, MessageVersion version, ref Message message)
    {
      if (error is FaultException) return;  

      var fault = new FaultException<MyFault>(new MyFault(), "I am a fault.");
      MessageFault messageFault = fault.CreateMessageFault();
      message = Message.CreateMessage(version, messageFault, fault.Action);
    }

    public bool HandleError(Exception error)
    {
      return false;
    }
  }
}

public class FaultAdderBehaviorAttribute : Attribute, IContractBehavior
{
  private Type[] faults;

  public FaultAdderBehaviorAttribute(params Type[] faults)
  {
    this.faults = faults;
  }

  public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
  {
  }

  public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  {
  }

  public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
  {
  }

  public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
  {
    foreach (OperationDescription op in contractDescription.Operations)
      foreach (Type fault in this.faults)
        op.Faults.Add(this.ExposeFault(fault));
  }

  private FaultDescription ExposeFault(Type fault)
  {
    string action = fault.Name;
    DescriptionAttribute attr = (DescriptionAttribute)Attribute.GetCustomAttribute(fault, typeof(DescriptionAttribute));

    if (attr != null) action = attr.Description;
    FaultDescription description = new FaultDescription(action);
    description.DetailType = fault;
    description.Name = fault.Name;
    return description;
  }
}

1 个答案:

答案 0 :(得分:1)

FaultAdderBehaviorAttribute存在问题,您担心fault.Action为空是正确的。

要使FaultException功能正常工作,您必须对每个故障都进行非空操作。

当您在操作本身上声明FaultContract时,您隐式使用WCF自动生成操作字符串(further details)的能力。但是,当您使用FaultAdderBehaviorAttribute时,已生成已声明操作的任何默认操作,并且您无法提供有效操作。