我的控制器呼叫我的业务服务。我通常将这些调用包装在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
}
我的问题是 - 出于可测试性目的,这两种方法中哪一种更受青睐?是否有其他模式可用于表明我的服务投入了?
答案 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组:
这些错误一旦被发现就应该作为例外引发,并且在应用程序的最外层被捕获。如果管道看起来像 WebServer - &gt; ServiceA - &gt; ServiceB - &gt; ServiceC - &gt; ServiceD 和 ServiceD 会引发应用程序错误,其他服务无法对其进行任何操作。如果他们可以 - 那不是应用程序错误!这只是系统流程之一,您应该为此定义结果状态(而不是异常)。 应该在Web服务器级别(“提前抛出,迟到”)“延迟”捕获异常,并将其转换为某些内部服务器/请求错误。
返回内部服务器错误完全可以 当您的数据库不可用时,您的应用程序或服务器配置错误,或者您有最简单的空引用异常(不确定忽略这些日志而不修复可修复的内容)。每当你不能 由于您自己的问题处理请求 - 当您返回50x错误时。