标准 .Net 异常在服务器端正确序列化,并在客户端反序列化。默认情况下,不是我们的。为什么 ?在调试会话期间向客户端发送业务异常可能是最佳实践:
- 无需将异常数据放入 [DataMember] 对象
- 比简单字符串 ( ExceptionFault<ExceptionDetail>
)拥有更多信息
但是在将代码投入生产时注意不要发送异常。如果您的服务暴露在互联网上,可能会导致安全漏洞向黑客泄露详细信息!
为了将业务异常发送给客户端,最佳(和一些强制性)实践是:
1/serviceDebugBehavior
打开
ServiceHost host = ...;
var debuggingBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
if (debuggingBehavior == null)
debuggingBehavior = new ServiceBehaviorAttribute();
#if DEBUG
debuggingBehavior.IncludeExceptionDetailInFaults = true;
#else
debuggingBehavior.IncludeExceptionDetailInFaults = false;
#endif
在xml中配置它也很容易
2/ 在服务接口上,声明一些 [FaultContract] :
[ServiceContract(Namespace="your namespace")]
public interface IBillingService
{
[OperationContract]
[FaultContract(typeof(BusinessException))]
void RaiseBusinessException();
}
3/ 应将业务异常标记为可序列化
[Serializable]
public class BusinessException : Exception
{ ... }
4/ 为了在客户端正确反序列化业务异常FaultException<BusinessException>
,实现一个负责反序列化的构造函数很重要。否则你会得到一个通用的FaultException
.
protected BusinessException(SerializationInfo info, StreamingContext context)
: base(info, context)
{}
5/ 如果您的异常中有一些额外的成员,请序列化/反序列化它们:
public DateTime CreationTime { get; set; }
protected BusinessException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
CreationTime = (DateTime)info.GetValue("CreationTime", typeof(DateTime));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("CreationTime", CreationTime);
}