1

我有一个 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.StackTrace 属性中。

但是,我不知道在哪里放置我的 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;
            }
        }
4

2 回答 2

2

What (I think) was suggested you do by throw a new simpler exception is that you translate the exceptions from the lower layers into new, higher level exceptions for consuming in the outer layers. The lower level exceptions are not suitable for consumption at the upper levels of the program.

For example, in LINQ to Entities, the method Single() will throw an InvalidOperationException when the sequence has no elements. However, this exception type is very common, so catching it in the user interface levels is hard to do: how would you differentiate between different possibilities of this exception being thrown (for example, modifying a read-only collection)? The solution is to translate the exception into another (new, user-defined) type that the application can easily handle.

Here is a simple example of the idea:

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);
        }
    }
}

Then the Program layer can catch the UserNotFoundException and know instantly what happened, and thus find the best way to explain the error to the user. The details will depend on the exact structure of your program, but something like this would work in an ASP.NET MVC app:

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);
     }
}
于 2012-12-27T19:49:56.320 回答
2

不仅仅是如何使用不同类型的异常处理。从功能上讲,您应该定义哪些层必须执行异常操作。

像数据层 => 除了 DataException 或 SQLException 之外,不要抛出任何东西。记录它们并将通用数据库异常返回给 UI。

业务层 => 记录并重新抛出简单的业务异常 UI 层 => 仅捕获业务异常并在业务异常内的消息中提醒它

一旦定义了所有这些,您就可以使用您所学和总结的内容来构建它。

于 2012-12-27T19:30:46.380 回答