对于服务,所有操作都可以抛出一组错误,因此为了集中这些错误,我创建了一个行为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;
}
}
答案 0 :(得分:1)
FaultAdderBehaviorAttribute
存在问题,您担心fault.Action
为空是正确的。
要使FaultException功能正常工作,您必须对每个故障都进行非空操作。
当您在操作本身上声明FaultContract时,您隐式使用WCF自动生成操作字符串(further details)的能力。但是,当您使用FaultAdderBehaviorAttribute
时,已生成已声明操作的任何默认操作,并且您无法提供有效操作。