2

我的服务只是调用放置整个业务逻辑的 BusinessLogicLayer 方法。我想知道处理 BL 引发的异常的最佳做法是什么?(不仅是致命异常,还有“逻辑”ApplicationExceptions,如我的 BL 在找不到用户时抛出的 UserNotFoundException)。

我应该在哪里将这些异常转换为客户将看到的 FaultExceptions?

我应该从 BL 抛出我的业务异常,然后将它们捕获到服务调用中并转换为 FaultException 并返回给客户端吗?或者 BL 应该引发已经“客户友好”的 FaultExceptions?

提前致谢 :)

4

2 回答 2

2

我会说从业务逻辑层抛出业务异常,这将使您的业务逻辑层与 wcf 实现分离。在服务调用中,您可以覆盖 applydispatchbehaviour 并在那里添加错误处理程序,例如

覆盖 IServiceBehavior.ApplyDispatchBehavior

 void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(new FaultErrorHandler());
            }
        }

故障错误处理程序

public class FaultErrorHandler : IErrorHandler
    {      

        void IErrorHandler.ProvideFault(System.Exception error, MessageVersion version, ref Message fault)
        {
            if (fault == null)
            {
                FaultException<[ExceptionType]> fe = new
                    FaultException<[ExceptionType]>([Exception cass],
                    error.Message, FaultCode.CreateReceiverFaultCode(new FaultCode("ServerException")));
                    MessageFault mf = fe.CreateMessageFault();
                    fault = Message.CreateMessage(version, mf, fe.Action);

            }
        }

    }
于 2012-07-19T11:30:43.317 回答
2

标准 .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);
}
于 2015-09-03T09:08:29.707 回答