如何告诉我的控制器我的服务引发异常

时间:2016-04-15 21:27:18

标签: c# design-patterns

我的控制器呼叫我的业务服务。我通常将这些调用包装在try / catch块中,以防我的服务抛出异常。

然后我想把那个try / catch块移到我的商业服务上,让他们告诉控制器他们是否扔了。

因此,我的商业服务可以返回如下界面:

interface IResult<T> {
    <T> Data { get; set; }
    Exception Exception { get; set; }
    bool HasException;
}

我的商业服务的签名将是:

public IResult<Product> GetProductByID(int id);

我的控制器会这样称呼它:

var result = serviceInstance.GetProductById(1);
if (result.HasException) {
    // handle exception here
}

我的问题是 - 出于可测试性目的,这两种方法中哪一种更受青睐?是否有其他模式可用于表明我的服务投入了?

1 个答案:

答案 0 :(得分:3)

我会尝试从更广泛的角度回答你的问题:

您应该以(希望)涵盖每个常见案例的方式设计您的系统。如果有意义的话 在数据库中找不到项目,并且您有一个特殊的流程来处理它,调用者必须能够从服务中获取该信息。 在编码方面,您最终有两个选择:

var res = serviceInstance.GetProductById(id);
switch (res.Status)
{
    case ResultStatus.OK:
        HandleExistingObject(res.Data);
        break;
    case ResultStatus.NotFound:
        HandleNotFound(id);
        break;
}

或者:

try
{
    var res = serviceInstance.GetProductById(id);
    //rest of code, basically HandleExistingObject() form above 
}
catch (ItemNotFoundException e)
{
    HandleNotFound(id);
    //This is the best case scenario. In many cases, you see something like this:
    // catch (Exception e)
    //... if(e is ItemNotFoundException && e.Message.Contains("dbError: not found")) ...
}

我相信大多数人会同意前者是更好的做法。我不会进入优点/缺点论点,但我要加上这个: 作为界面的一部分显示异常的唯一方法是通过XML文档。太松散的类型,反直觉和容易出错。 新程序员可以轻松地更改为抛出异常的类型,而不会意识到其他服务依赖于该特定异常。然而 程序员破坏强大的类型接口是非常罕见的。

那么,什么时候应该抛出异常?

一旦映射了系统中所有可能的流,每个未处理的情况都是例外。 当服务遇到错误时,它不是设计要解决的,意味着 - 您的整个系统无意解决 - 服务应记录所有可能的信息,终止当前流(或请求)并返回内部服务器错误。

这类错误一般可分为3组:

  1. 请求错误 - 未经授权的请求,无效的请求参数等。客户负责的每种错误。
  2. 应用程序错误 - 系统设计错误。例如,当要求ProductService将产品X添加到用户Y时,用户Y甚至不存在(并且创建非现有用户不是ProductService的工作)。
  3. 内部服务错误 - 主要是编码错误(空引用,索引超出边界等)。
  4. 这些错误一旦被发现就应该作为例外引发,并且在应用程序的最外层被捕获。如果管道看起来像 WebServer - &gt; ServiceA - &gt; ServiceB - &gt; ServiceC - &gt; ServiceD ServiceD 会引发应用程序错误,其他服务无法对其进行任何操作。如果他们可以 - 那不是应用程序错误!这只是系统流程之一,您应该为此定义结果状态(而不是异常)。 应该在Web服务器级别(“提前抛出,迟到”)“延迟”捕获异常,并将其转换为某些内部服务器/请求错误。

    返回内部服务器错误完全可以 当您的数据库不可用时,您的应用程序或服务器配置错误,或者您有最简单的空引用异常(确定忽略这些日志而不修复可修复的内容)。每当你不能 由于您自己的问题处理请求 - 当您返回50x错误时。