Wcf 服务异常良好实践

Posted

技术标签:

【中文标题】Wcf 服务异常良好实践【英文标题】:Wcf service exception good practices 【发布时间】:2012-09-20 18:54:04 【问题描述】:

我正在开发一个分布式应用程序。在其中,我必须验证角色和权限集。 抛出异常(例如,未经授权的访问)是一种好习惯吗? 还是我应该向客户端发送一些消息?

【问题讨论】:

一旦你知道用户是未经授权的,你不想在任何情况下执行任何进一步的代码,所以抛出异常是好的。 抛出异常真的好吗?引用 Oreilly.Programming.WCF.Services.3rd.Edition:第 6 章故障:“异常和异常处理等概念是特定于技术的,不应超越服务边界。此外,客户端处理错误的尝试总是会导致增加耦合。”但是我们在我的公司里肯定会争论这个 【参考方案1】:

在您的服务操作中,您可以指定一个 FaultContract 来满足这两个目的,如下所示:

[OperationContract]
[FaultContract(typeof(MyServiceFault))]
void MyServiceOperation();

请注意,MyServiceFault 必须使用 DataContract 和 DataMember 属性进行标记,就像使用复杂类型一样:

[DataContract]
public class MyServiceFault

    private string _message;

    public MyServiceFault(string message)
    
        _message = message;
    

    [DataMember]
    public string Message  get  return _message;  set  _message = value;  

在服务端,您可以:

throw new FaultException<MyServiceFault>(new MyServiceFault("Unauthorized Access"));

在客户端:

try

    ...

catch (FaultException<MyServiceFault> fault)

    // fault.Detail.Message contains "Unauthorized Access"

【讨论】:

对于 OP:您不想“抛出异常”。你想“返回故障”。这就是这个答案向您展示的方法。 我个人认为这是最优雅的方法。委托给 WCF 以展示如何处理异常。谢谢【参考方案2】:

好吧,您可以在 WCF 服务实现方法中捕获所有异常并将它们作为 FaultExceptions 重新抛出。通过这种方式,异常将在客户端上重新抛出,并带有您选择的消息:

[OperationContract]
public List<Customer> GetAllCustomers()

    try
    
        ... code to retrieve customers from datastore
    
    catch (Exception ex)
    
        // Log the exception including stacktrace
        _log.Error(ex.ToString());

        // No stacktrace to client, just message...
        throw new FaultException(ex.Message);
    

为避免将意外错误转发回客户端,最好不要在服务器端的代码中抛出异常实例。而是创建一种或多种您自己的异常类型并抛出它们。通过这样做,您可以区分意外的服务器处理错误和由于无效请求等引发的错误:

public List<Customer> GetAllCustomers()

    try
    
        ... code to retrieve customers from datastore
    
    catch (MyBaseException ex)
    
         // This is an error thrown in code, don't bother logging it but relay
         // the message to the client.
         throw new FaultException(ex.Message);
    
    catch (Exception ex)
    
        // This is an unexpected error, we need log details for debugging
        _log.Error(ex.ToString());

        // and we don't want to reveal any details to the client
        throw new FaultException("Server processing error!");
    

【讨论】:

@Yakov:您选择的日志框架中的一个类。日志记录代码主要用于说明如何针对不同类型的错误进行不同的日志记录。如果您正在寻找一个好的日志框架,请查看 log4net。非常成熟且易于使用。 有人可以评论为什么这个答案没有得到更多的支持以及为什么接受的答案更好?更复杂,实现同样的事情? @Esko:据我了解,这些答案使用相同的功能:通过抛出 FaultException 来实现 SOAP-Fault。唯一的区别是,这个答案只抛出一个基本的 FaultExeption,而接受的答案显示如何自定义 FaultExeption。自定义使您能够在客户端更具体地处理不同类型的服务器端异常并传递更多信息。您可以在非 WCF 上下文中比较抛出 FaultExeption 与抛出 FaultException 与抛出异常与抛出 MyCustomException。【参考方案3】:

如果您不使用 basicHTTPBinding,则抛出一般的 Dot Net 异常会使服务客户端代理和服务器通道进入故障状态 ...为避免这种情况,您应该始终抛出 FaultException 来自服务... from you catch 块只需使用:

throw new FaultException("Your message to the clients");

【讨论】:

以上是关于Wcf 服务异常良好实践的主要内容,如果未能解决你的问题,请参考以下文章

服务端增加WCF服务全局异常处理机制

大型 WCF 服务的最佳实践?

调用 WCF 服务的最佳实践 [重复]

WCF:在嵌套服务调用中保留内部异常

WCF 服务代理生命周期的最佳实践?

WCF 异常:找不到与端点的方案 http 匹配的基地址