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

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

【问题讨论】:

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

标签: c# .net wcf web-services


【解决方案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");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 2016-06-25
    相关资源
    最近更新 更多