Controller中的exception处理(ASP.NET MVC)

当您从控制器中的操作调用的自己的代码抛出exception时应该如何处理? 我看到很多最佳实践的例子,其中根本没有try-catch语句。 例如,从存储库访问数据:

public ViewResult Index() { IList customModels = _customModelRepository.GetAll(); return View(customModels); } 

显然,如果对无法访问的数据库进行调用,并且我们正在使用像Entity Framework这样的ORM,则此代码可能会抛出exception。

但是,我能看到的所有事情都会发生exception,并且会向用户显示一条令人讨厌的错误消息。

我知道HandleError属性,但据我所知,如果发生未处理的exception,它主要用于将您重定向到错误页面。

当然,这段代码可以包装在try-catch中,但不能很好地分离,特别是如果你有更多的逻辑:

 public ViewResult Index() { if (ValidationCheck()) { IList customModels = new List(); try { customModels = _customModelRepository.GetAll(); } catch (SqlException ex) { // Handle exception } if (CustomModelsAreValid(customModels)) // Do something else // Do something else } return View(); } 

以前我已经提取出所有可能会将数据库调用之类的exception抛出到DataProvider类中的代码,该类处理错误并返回消息以向用户显示消息。

我想知道处理这个问题的最佳方法是什么? 我并不总是想返回错误页面,因为有些例外不应该这样做。 相反,应该以正常视图显示给用户的错误消息。 我以前的方法是正确的还是有更好的解决方案?

我做了三件事来显示更多用户友好的消息:

  1. 利用全局exception处理程序。 对于MVC:Global.asax中的Application_Error。 在这里学习如何使用它: http : //msdn.microsoft.com/en-us/library/24395wz3(v = vs.100).aspx
  2. 我将Exception子类化为UserFriendlyException。 我尽我所能在我的所有底层服务类中抛出这个UserFriendlyException而不是一个普通的旧Exception。 我总是尝试将用户有意义的消息放在这些自定义exception中。 其主要目的是能够在Application_Error方法中对exception进行类型检查。 对于UserFriendlyExceptions,我只使用我在服务中深入设置的用户友好消息,例如“嘿!91度不是有效的纬度值!”。 如果它是常规exception,那么在某些情况下我没有处理,所以我显示了一个更通用的错误消息,比如“哎呀,出了点问题!我们会尽力解决这个问题!”。
  3. 我还创建了一个ErrorController,负责呈现用户友好的视图或JSON。 这是控制器,其方法将从Application_Error方法调用。

编辑:我想我会提到ASP.NET Web API,因为它密切相关。 因为Web API端点的使用者不一定是浏览器,所以我喜欢稍微处理错误。 我仍然使用“FriendlyException”(上面的#2),但不是重定向到ErrorController,而是让我的所有端点返回某种包含Error属性的基类型。 因此,如果exception一直到Web API控制器,我确保将该错误粘贴在API响应的Error属性中。 此错误消息将是从API控制器所依赖的类中冒出的友好消息,或者如果exception类型不是FriendlyException,则它将是通用消息。 这样,消费客户端可以简单地检查API响应的Error属性是否为空。 如果存在错误则显示消息,否则照常进行。 好消息是,由于友好的消息概念,消息对于用户而言可能比通用的“错误!”更有意义。 信息。 在使用Xamarin编写移动应用程序时,我使用此策略,我可以在我的Web服务和iOS / Android应用程序之间共享我的C#类型。

使用Asp.Net MVC,您还可以为您的控制器覆盖OnException方法。

 protected override void OnException(ExceptionContext filterContext) { if (filterContext.ExceptionHandled) { return; } filterContext.Result = new ViewResult { ViewName = ... }; filterContext.ExceptionHandled = true; } 

这允许您重定向到自定义错误页面,如果您愿意,可以使用引用该exception的消息。

我使用了OnException覆盖,因为我有几个项目引用到一个具有处理错误的Controller的项目:

安全/ HandleErrorsController.cs

 protected override void OnException(ExceptionContext filterContext) { MyLogger.Error(filterContext.Exception); //method for log in EventViewer if (filterContext.ExceptionHandled) return; filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; filterContext.Result = new JsonResult { Data = new { Success = false, Error = "Please report to admin.", ErrorText = filterContext.Exception.Message, Stack = filterContext.Exception.StackTrace }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; filterContext.ExceptionHandled = true; } 

像这样的所有问题都不是很有建设性,因为答案总是“它取决于”,因为有很多方法可以处理error handling。

许多人喜欢使用HandleError方法,因为任何exception基本上都是不可恢复的。 我的意思是,如果你不能归还物体,你打算做什么? 无论如何你会向他们展示一个错误,对吧?

问题变成了,你想如何向他们展示错误。 如果显示错误页面是可以接受的,那么HandleError工作正常,并提供了一个记录错误的简单位置。 如果您正在使用Ajax或想要更高级的东西,那么您需要开发一种方法来实现这一点。

你谈论一个DataProvider类。 这基本上就是你的存储库。 为什么不将它构建到您的存储库中?