WCF服务创建与抛出强类型SOAP Fault

时间:2021-06-30 18:55:52

原创地址:http://www.cnblogs.com/jfzhu/p/4060666.html

转载请注明出处

前面的文章《WCF服务的异常消息》中介绍过,如果WCF Service发生异常时,Service会将异常序列化为SOAP Fault并发送给客户端。

默认情况下,出于安全原因,WCF Service中未处理的异常的详细信息不会包括在发送给客户的SOAP Fault里,你只能看到一个通用的SOAP Fault(“The server was unable to process the request due to an internal error.”)。在调试程序的时候,如果想在SOAP Fault中包含异常的详细信息,可以修改服务器的配置文件。

<behaviors>
<serviceBehaviors>
<behavior name="includeExceptionDetails">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>

SOAP Fault是XML格式,与平台无关。通常一个SOAP Fault包含以下节点

(1) faultcode

(2) faultstring

(3) detail

Detail节点可以用来包括自定义XML信息。

WCF Service在发生异常时应抛出FaultException或FaultException<T>,而不应该抛出.NET Exception,出于以下两个原因:

(1)未处理的.NET Exception会使服务器与客户端之间的channel变为Fault状态,继而导致client proxy无法使用。

(2).NET Exception只能被.NET平台理解,而FaultException与平台无关。如果想跨平台使用,需要使用FaultException。

下面还是以中《WCF服务的异常消息》的例子来分别演示如何抛出与处理FaultException与强类型的FaultException<T>。

(一)使用FaultException

IDemoService.cs:

using System.ServiceModel;

namespace WCFDemo
{
[ServiceContract(Name = "IDemoService")]
public interface IDemoService
{
[OperationContract]
int Divide(int numerator, int denominator);
}
}

DemoService.cs:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation; namespace WCFDemo
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DemoService : IDemoService
{
public int Divide(int numerator, int denominator)
{
if (denominator == )
{
throw new FaultException("Denominator cannot be ZERO!", new FaultCode("DivideByZeroFault"));
}
return numerator / denominator;
}
}
}

client:

private void buttonCalculate_Click(object sender, EventArgs e)
{
try
{
textBoxResult.Text = demoServiceClient.Divide(Convert.ToInt32(textBoxNumerator.Text), Convert.ToInt32(textBoxDenominator.Text)).ToString();
}
catch (FaultException fault)
{
MessageBox.Show(fault.Code + " - " + fault.Message);
}
}

WCF服务创建与抛出强类型SOAP Fault

WCF服务创建与抛出强类型SOAP Fault

SOAP Fault XML

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:DivideByZeroFault</faultcode>
<faultstring xml:lang="en-US">Denominator cannot be ZERO!</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>

(二)使用强类型FaultException<T>

(1)创建一个自定义SOAP Fault类

DivideByZeroFault.cs:

using System.Runtime.Serialization;

namespace WCFDemo
{
[DataContract]
public class DivideByZeroFault
{
[DataMember]
public string Error { get; set; } [DataMember]
public string Detail { get; set; }
}
}

(2) 在Service方法上使用FaultContractAttribute来指示哪个操作可以使用哪个Fault

IDemoService.cs:

using System.ServiceModel;

namespace WCFDemo
{
[ServiceContract(Name = "IDemoService")]
public interface IDemoService
{
[FaultContract(typeof(DivideByZeroFault))]
[OperationContract]
int Divide(int numerator, int denominator);
}
}

DemoService.cs:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation; namespace WCFDemo
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DemoService : IDemoService
{
public int Divide(int numerator, int denominator)
{
try
{
return numerator / denominator;
}
catch (DivideByZeroException ex)
{
DivideByZeroFault fault = new DivideByZeroFault();
fault.Error = ex.Message;
fault.Detail = "Denominator cannot be ZERO!";
throw new FaultException<DivideByZeroFault>(fault);
}
}
}
}

client:

private void buttonCalculate_Click(object sender, EventArgs e)
{
try
{
textBoxResult.Text = demoServiceClient.Divide(Convert.ToInt32(textBoxNumerator.Text), Convert.ToInt32(textBoxDenominator.Text)).ToString();
}
catch (FaultException<DemoServiceReference.DivideByZeroFault> fault)
{
MessageBox.Show(fault.Detail.Error + " - " + fault.Detail.Detail);
}
}

WCF服务创建与抛出强类型SOAP Fault

WCF服务创建与抛出强类型SOAP Fault

返回的SOAP Fault XML:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="en-US">The creator of this fault did not specify a Reason.</faultstring>
<detail>
<DivideByZeroFault xmlns="http://schemas.datacontract.org/2004/07/WCFDemo" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Detail>Denominator cannot be ZERO!</Detail>
<Error>Attempted to divide by zero.</Error>
</DivideByZeroFault>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>

WCF服务创建与抛出强类型SOAP Fault