异常处理机制及分类
常见的异常:
异常的分级分类:
NET调用过程中产生的异常,对于终端用户来说这些异常不应该出现,应该在系统测试阶段就解决。
数据库访问异常:给只读的属性赋值 ,属性的值与类型不匹配, 在实体的属性值设为NULL之后,仍然去访问它的属性性 等。
应用系统内部异常:是应用系统自己定义的异常,对于终端用户来说这些异常不应该出现,主要用来支持内部系统的决策,比如是否可恢复等,通常是将.NET异常转化而来。
应用系统业务逻辑异常:是应用系统自己定义,用来向终端用户报告业务逻辑错误或将系统内部异常转化为终端用户可以理解的错误消息,终端用户应该只能看到此类异常。
异常的处理策略
对于异常来说一个明确的处理策略就是只处理或封装你明确知道的异常,通过测试来暴露所有可能出错的异常,其中有的异常会被作为bug修改,有的异常会因为无法避免而暴露出来成为我们明确知道的异常,这时我们需要决策这类异常该如何处理(忽略,尝试,报告用户)
使用
应用程序异常的处理方式:
使用try-catch-finally块捕获异常,基本格式如下:
try { //获取并使用资源,可能出现异常 } catch(Exception e) { //是否抛出异常 } finally { //无论什么情况(即使在catch块中return)下,都会执行该块的代码(如:关闭文件) //另外需要说明的是,在finally块中使用任何break、continue、return退出都是非法的。 }
ASP.NET MVC异常处理:
MVC中有三个过滤器,其中两个为:Action filter和 Authorization filter。第三个过滤器为异常过滤器(Exception Filters)。
什么是异常过滤器(Exception Filters)?
异常过滤器与其他过滤器的用法相同,可当作属性使用。使用异常过滤器的基本步骤:
1. 使它们可用
2. 将过滤器作为属性,应用到action 方法或控制器中。我们也可以在全局层次使用异常过滤器。
异常过滤器的作用是什么?,是否有自动执行的异常过滤器?
一旦action 方法中出现异常,异常过滤器就会控制程序的运行过程,开始内部自动写入运行的代码。MVC为我们提供了编写好的异常过滤器:HandeError。
当action方法中发生异常时,过滤器就会在“~/Views/[current controller]”或“~/Views/Shared”目录下查找到名称为”Error”的View,然后创建该View的ViewResult,并作为响应返回。
接下来我们会讲解一个Demo,帮助我们更好的理解异常过滤器的使用。
已经实现的上传文件功能,很有可能会发生输入文件格式错误。因此我们需要处理异常。
1. 创建含错误信息的样本文件,包含一些非法值,如图,Salary就是非法值。
2. 运行,查找异常,点击上传按钮,选择已建立的样本数据,选择上传。
3. 激活异常过滤器
当自定义异常被捕获时,异常过滤器变为可用。为了能够获得自定义异常,打开Web.config文件,在System.Web.Section下方添加自定义错误信息。
1: <system.web> 2: <customErrors mode="On"></customErrors>
4. 创建Error View
在“~/Views/Shared”文件夹下,会发现存在“Error.cshtml”文件,该文件是由MVC 模板提供的,如果没有自动创建,该文件也可以手动完成。
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Error</title> </head> <body> <hgroup> <h1>Error.</h1> <h2>An error occurred while processing your request.</h2> </hgroup> </body> </html>
5. 绑定异常过滤器
将过滤器绑定到action方法或controller上,不需要手动执行,打开 App_Start folder文件夹中的 FilterConfig.cs文件。在 RegisterGlobalFilters 方法中会看到 HandleError 过滤器已经以全局过滤器绑定成功。
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());//ExceptionFilter
filters.Add(new AuthorizeAttribute());
}
如果需要删除全局过滤器,那么会将过滤器绑定到action 或controller层,但是不建议这么做,最好是在全局中应用如下:
[AdminFilter]
[HandleError]
public async Task<ActionResult> Upload(FileUploadViewModel model)
{<actionresult>
</actionresult>
6. 运行
7. 在View中显示错误信息
将Error View转换为HandleErrorInfo类的强类型View,并在View中显示错误信息。
@model HandleErrorInfo @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Error</title> </head> <body> <hgroup> <h1>Error.</h1> <h2>An error occurred while processing your request.</h2> </hgroup> Error Message :@Model.Exception.Message<br /> Controller: @Model.ControllerName<br /> Action: @Model.ActionName </body> </html>
8. 运行测试
Handle error属性能够确保无论是否出现异常,自定义View都能够显示,但是它的能力在controller和action 方法中是受限的。不会处理“Resource not found”这类型的错误。
运行应用程序,输一些奇怪的URL
9. 创建 ErrorController控制器,并创建Index方法,代码如下:
public class ErrorController : Controller { // GET: Error public ActionResult Index() { Exception e=new Exception("Invalid Controller or/and Action Name"); HandleErrorInfo eInfo = new HandleErrorInfo(e, "Unknown", "Unknown"); return View("Error", eInfo); } }
10. 在非法URL中显示自定义Error视图
可在 web.config中定义“Resource not found error”的设置,如下:
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Error/Index"/>
</customErrors>
11. 使 ErrorController 全局可访问。
将AllowAnonymous属性应用到 ErrorController中,因为错误控制器和index方法不应该只绑定到认证用户,也很有可能用户在登录之前已经输入错误的URL。
[AllowAnonymous]
public class ErrorController : Controller
{
12. 运行
总结:
在实际的项目中,我们一般不要将异常直接抛出给客户,我们在编写程序时,已经考虑程序的容错性,在程序捕获到异常后,尽量去恢复程序,或者将异常信息写入日志,让程序进入错误页。如果出现比较严重的异常,最后将异常抛出,终止程序。