SOAP 错误可将错误情况信息从服务传达到客户端,在双工情况下,还可以以互操作方式从客户端传达到服务。 本主题讨论何时以及如何定义自定义错误内容并指定哪些作可以返回它们。 有关服务(或双工客户端)如何发送这些错误以及客户端或服务应用程序如何处理这些错误的详细信息,请参阅发送和接收错误。 有关 Windows Communication Foundation (WCF) 应用程序中错误处理的概述,请参阅 “在协定和服务中指定和处理错误”。
概述
声明的 SOAP 错误是指具有 System.ServiceModel.FaultContractAttribute 指定自定义 SOAP 错误类型的操作。 未声明的 SOAP 错误是指那些未在相应操作的协定中指定的错误。 本主题帮助你识别错误条件,为服务创建一个故障合同。该合同可供客户端使用,以便在自定义 SOAP 错误通知时正确处理这些错误条件。 基本任务按顺序排列:
定义服务客户端应了解的错误条件。
为这些错误条件定义 SOAP 错误的自定义内容。
标记您的操作,以便它们引发的特定 SOAP 错误会在 WSDL 中向客户公开。
定义客户端应了解的错误条件
SOAP 故障是公开描述的消息,这些消息包含有关特定操作的故障信息。 由于它们与其他操作消息一起在 WSDL 中被描述,因此,客户端知道并预计在调用操作时处理此类故障。 但是,由于 WCF 服务是用托管代码编写的,因此确定哪些托管代码中的错误条件应转换为错误并返回给客户端,这为你提供了将服务中的错误条件和 bug 与与客户端的正式错误处理分开的机会。
例如,下面的代码示例演示一个操作,该操作采用两个整数并返回另一个整数。 这里可引发若干个异常,因此设计错误协定时,必须确定哪些是客户端最重要的错误情况。 在这种情况下,服务应检测 System.DivideByZeroException 异常。
[ServiceContract]
public class CalculatorService
{
[OperationContract]
int Divide(int a, int b)
{
if (b==0) throw new Exception("Division by zero!");
return a/b;
}
}
<ServiceContract> _
Public Class CalculatorService
<OperationContract> _
Public Function Divide(a As Integer, b As Integer) As Integer
If b = 0 Then Throw New DivideByZeroException("Division by zero!")
Return a / b
End Function
End Class
在上面的示例中,该操作可返回一个特定的除以零的自定义 SOAP 错误、可返回一个特定于数学运算但包含特定的除以零信息的自定义错误、可为若干个不同错误情况返回多个错误,或根本不返回 SOAP 错误。
定义错误条件的内容
将错误条件标识为可以有效地返回自定义 SOAP 错误的错误条件后,下一步是定义该错误的内容并确保内容结构可以序列化。 上一部分中的代码示例显示了特定于 Divide
操作的错误,但如果对 Calculator
服务执行其他操作,则单个自定义 SOAP 错误可以通知客户端所有计算器错误条件,包括 Divide
在内。 下面的代码示例演示如何创建自定义 SOAP 错误, MathFault
该错误可以报告使用所有数学运算(包括 Divide
)所犯的错误。 虽然类可以指定一个操作(Operation
属性)并描述问题的值(ProblemType
属性),但为了能够在自定义 SOAP 故障中传输到客户端,类及其这些属性必须是可序列化的。 因此,System.Runtime.Serialization.DataContractAttribute 和 System.Runtime.Serialization.DataMemberAttribute 属性被用于使类型及其属性可序列化,并尽可能实现互操作性。
// Define a math fault data contract
[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public class MathFault
{
private string operation;
private string problemType;
[DataMember]
public string Operation
{
get { return operation; }
set { operation = value; }
}
[DataMember]
public string ProblemType
{
get { return problemType; }
set { problemType = value; }
}
}
' Define a math fault data contract
<DataContract([Namespace]:="http://Microsoft.ServiceModel.Samples")> _
Public Class MathFault
Private m_operation As String
Private m_problemType As String
<DataMember()> _
Public Property Operation() As String
Get
Return m_operation
End Get
Set(ByVal value As String)
m_operation = value
End Set
End Property
<DataMember()> _
Public Property ProblemType() As String
Get
Return m_problemType
End Get
Set(ByVal value As String)
m_problemType = value
End Set
End Property
End Class
有关如何确保数据可序列化的详细信息,请参阅 在服务协定中指定数据传输。 关于 System.Runtime.Serialization.DataContractSerializer 提供的序列化支持的列表,请参阅 数据协定序列化程序支持的类型。
标记操作以建立错误协定
定义作为自定义 SOAP 故障的一部分返回的可序列化数据结构后,最后一步是将操作约定标记为抛出该类型的 SOAP 故障。 为此,请使用 System.ServiceModel.FaultContractAttribute 属性并传递已构造的自定义数据类型的类型。 下面的代码示例演示如何使用 FaultContractAttribute 特性指定 Divide
操作可以返回类型为 MathFault
的 SOAP 错误。 其他基于数学的运算现在也可以指定它们可以返回MathFault
。
[OperationContract]
[FaultContract(typeof(MathFault))]
int Divide(int n1, int n2);
<OperationContract()> _
<FaultContract(GetType(MathFault))> _
Function Divide(ByVal n1 As Integer, ByVal n2 As Integer) As Integer
操作可以通过标记多个FaultContractAttribute属性来指定它返回多个自定义错误。
下一步是在操作实现中实施故障协定,请参阅“发送和接收故障”主题。
SOAP、WSDL 和互作性注意事项
在某些情况下,尤其是在与其他平台互作时,控制错误出现在 SOAP 消息中的方式或 WSDL 元数据中描述的方式可能很重要。
该 FaultContractAttribute 属性具有一个 Name 属性,该属性允许控制在该错误的元数据中生成的 WSDL 错误元素名称。
根据 SOAP 标准,故障可以有一个 Action
、一个 Code
和一个 Reason
。
Action
由 Action 属性控制。
Code 属性和 Reason 属性都是 System.ServiceModel.FaultException 类的属性,该类是泛型 System.ServiceModel.FaultException<TDetail> 的父类。 该 Code
属性包括一个 SubCode 成员。
访问生成错误的非服务时,存在某些限制。 WCF 只支持具有符合架构描述且与数据协定兼容的详细信息类型的错误。 例如,如上所述,WCF 不支持在其详细信息类型中使用 XML 属性的故障,也不支持在详细信息部分中具有多个顶级元素的错误。