如何在多层程序中重新抛出异常
本文关键字:抛出异常 程序 | 更新日期: 2023-09-27 17:49:36
我有一个MVC EF5设置,类:
-
Program
-这是控制器 -
UserInterface
-这是视图,负责显示和提示数据。 -
DataAccess
-模型,这创建,读取,更新和删除数据在我的EF模型类
当DataAccess类尝试在我的数据库上执行CRUD操作时,如果它捕获到错误,则需要对其进行处理,我的UserInterface类需要向用户打印消息,并在必要时报告任何错误。因此,当发生错误时,它需要首先通过程序类,然后到UserInterface类,因为数据层不应该直接与表示层通信。
有人建议我不传递或返回异常给调用函数,但我应该"向上面的层抛出一个新的更简单的异常"。所有这些关于异常的讨论让我感到困惑,因为我对异常的经验仅限于这种格式:
try
{
// stuff
}
catch (exception ex)
{
console.writeline(ex.ToString());
}
我自己做了一些研究,试图找到这个问题的答案,我学到了一些东西,但不知道如何把它们放在一起:
我学会了:
-
throw;
重新抛出异常并保留堆栈跟踪 -
throw ex
抛出一个现有的异常,比如在catch块中捕获的异常。并重置堆栈跟踪。 - 有一个属性叫做Exception.StackTrace。我知道每次抛出异常时,调用堆栈中的帧都会记录到exception中。加属性。
然而,我不知道在哪里放置我的try/catch块来利用重新抛出
是不是类似下面的代码?还是我没理解这是怎么回事?
编辑:(增加了一点,使这个猜测对其他人有意义)
void MethodA()
{
try
{
MethodB();
}
catch (MyExceptionType ex)
{
// Do stuff appropriate for MyExceptionType
throw;
}
}
void MethodB()
{
try
{
MethodC();
}
catch (AnotherExceptionType ex)
{
// Do stuff appropriate for AnotherExceptionType
throw;
}
}
void MethodC()
{
try
{
// Do Stuff
}
catch (YetAnotherExceptionType ex)
{
// Do stuff appropriate for YetAnotherExceptionType
throw;
}
}
不仅仅是如何使用不同类型的异常处理。在功能上,你应该定义什么层必须做什么异常。
像数据层=>不要抛出除DataException或SQLException以外的任何异常。记录它们,并将一个通用的数据库异常扔回UI。
业务层=>记录并重新抛出简单的业务异常UI层=>只捕获业务异常并在业务异常内部的消息中警告它
一旦所有这些都定义好了,您就可以使用您所学到的和在问题中总结的内容来构建它。
抛出一个新的更简单的异常建议您做的(我认为)是将来自较低层的异常转换为新的、更高级别的异常,以便在外层中使用。较低级别的异常不适合在程序的上层使用。
例如,在LINQ to Entities中,当序列没有元素时,方法Single()
将抛出InvalidOperationException
。然而,这种异常类型非常常见,因此很难在用户界面级别捕获它:您如何区分抛出该异常的不同可能性(例如,修改只读集合)?解决方案是将异常转换为应用程序可以轻松处理的另一种(新的、用户定义的)类型。
下面是一个简单的例子:
public class MyUserService {
public User GetById(int id) {
try {
using(var ctx = new ModelContainer()) {
return ctx.Where(u => u.Id == id).Single();
}
}
catch(InvalidOperationException) {
// OOPs, there is no user with the given id!
throw new UserNotFoundException(id);
}
}
}
然后Program
层可以捕获UserNotFoundException并立即知道发生了什么,从而找到向用户解释错误的最佳方法。具体细节将取决于您的程序的确切结构,但类似这样的东西将在ASP中工作。. NET MVC应用:
public class MyUserController : Controller {
private MyUserService Service = new MyUserService();
public ActionResult Details(int id) {
User user;
try {
user = Service.GetById(id);
}
catch(UserNotFoundException) {
// Oops, there is no such user. Return a 404 error
// Note that we do not care about the InvalidOperationException
// that was thrown inside GetById
return HttpNotFound("The user does not exist!");
}
// If we reach here we have a valid user
return View(user);
}
}