异常处理是每一个系统都必须要有的功能,尤其对于Web系统而言,简单、统一的异常处理模式尤为重要,当打算使用ASP.NET MVC来做项目时,第一个数据录入页面就遇到了这个问题。

在之前的ASP.NET WebForm项目中,一般情况下都是在Application_Error事件处理器和ScriptManager_AsyncPostBackError事件处理器里面进行,在ASP.NET MVC中用这两种方法似乎都不合适了,该放在哪儿呢?总不至于在每个Action里面都放一个try{...}catch{...}吧。

在ScottGu的博客里面提到了一个类:HandleErrorAttribute,似乎是用于处理异常的,于是使用HandleErrorAttribute来做个尝试,(说明,如果使用了该类型,并且想把异常显示在自已指定的View,则必须在web.config里面的<system.web>节点加上<customErrors mode="On" />)发现HandleError的确比较好用,可以使用其View属性指定异常后跳转的页面,可以针对不同的异常类型跳到不同的异常显示View,而且也可以不跳转到异常显示View,显示到当前View,例:

[HttpPost]
[HandleError(View = "Create", ExceptionType = typeof(Exception))]
public ActionResult Create(string someParam)
{
    throw new Exception("oops...");
}

当异常发生时,页面还会跳回到Create,只是这里有点小问题,用户在页面上输入了很多东西,你提示个异常不至于把他辛辛苦苦输了半天的东西都没有了吧,把这样的项目送出去,迟早是要改回来的。

打开HandleErrorAttribute的源代码可以看其关键部分:

public virtual void OnException(ExceptionContext filterContext) {
    if (filterContext == null) {
        throw new ArgumentNullException("filterContext");
    }
    if (filterContext.IsChildAction) {
        return;
    }
 
    // If custom errors are disabled, we need to let the normal ASP.NET exception handler
    // execute so that the user can see useful debugging information.
    if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) {
        return;
    }
 
    Exception exception = filterContext.Exception;
 
    // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
    // ignore it.
    if (new HttpException(null, exception).GetHttpCode() != 500) {
        return;
    }
 
    if (!ExceptionType.IsInstanceOfType(exception)) {
        return;
    }
 
    string controllerName = (string)filterContext.RouteData.Values["controller"];
    string actionName = (string)filterContext.RouteData.Values["action"];
    HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
    filterContext.Result = new ViewResult {
        ViewName = View,
        MasterName = Master,
        ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
        TempData = filterContext.Controller.TempData
    };
    filterContext.ExceptionHandled = true;
    filterContext.HttpContext.Response.Clear();
    filterContext.HttpContext.Response.StatusCode = 500;
 
    // Certain versions of IIS will sometimes use their own error page when
    // they detect a server error. Setting this property indicates that we
    // want it to try to render ASP.NET MVC's error page instead.
    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}

可以很清楚的看到,MVC实际上是使用刚才我们指定的View名称新建了一个ViewResult,然后将这个ViewResult交给了InvokeActionResult方法,最终显示给了用户。在这个过程中,新的ViewResult的ViewData被设定为HandleErrorInfo了,没有将Create上的数据放进ViewData,尽管在之后显示的Create视图的Request里还保存着之前的Params内容,但是数据却没有加载上去,我也没有去深究,感觉如果在这里直接把filterContext.Controller中的ViewData直接作为新的ViewResult的ViewData的话,肯定是可以显示提交之前的数据的(因为如果将异常代码包在try...catch...里面是可以在异常后显示之前数据的)。

于是自已新建一个ExceptionFitler:

public class CustomHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        filterContext.Controller.ViewData["Exception"] = filterContext.Exception;
        filterContext.Result = new ViewResult() { ViewName = filterContext.Controller.ControllerContext.RouteData.Values["Action"].ToString(), ViewData = filterContext.Controller.ViewData };
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

类名起的不咋的,将就着用吧:)

将原来的Action修改如下:

[HttpPost]
[CustomHandleError]
public ActionResult Create(string Name)
{
    throw new Exception("oops...");
}

Create.csthml中加入如下代码:

if (ViewData["Exception"] != null)
{
    var ex = ViewData["Exception"] as Exception;
    @ex.Message
}

F5,果然在提交后又回到了原来视图,而且之前填写的数据都还在。

3月19日完善如下:-----------------------------------------

namespace System.Web.Mvc
{
    public class HandleExceptionAttribute : HandleErrorAttribute, IExceptionFilter
    {
        #region IExceptionFilter Members
 
        public override void OnException(ExceptionContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            if (filterContext.IsChildAction)
            {
                return;
            }
 
            // If custom errors are disabled, we need to let the normal ASP.NET exception handler
            // execute so that the user can see useful debugging information.
            if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
            {
                return;
            }
 
            Exception exception = filterContext.Exception;
 
            // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
            // ignore it.
            if (new HttpException(null, exception).GetHttpCode() != 500)
            {
                return;
            }
 
            if (!ExceptionType.IsInstanceOfType(exception))
            {
                return;
            }
 
            string actionName = (string)filterContext.RouteData.Values["action"];
            filterContext.Controller.ViewData["Exception"] = exception;
            filterContext.Result = new ViewResult() { ViewName = actionName, ViewData = filterContext.Controller.ViewData };
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }
 
        #endregion
    }
 
    public static class HandleExceptionHelper
    {
        public static Exception Exception(this HtmlHelper htmlhelper)
        {
            var exception = htmlhelper.ViewContext.Controller.ViewData["Exception"] as Exception;
            return exception;
        }
    }
}

View运用如下:

if (@Html.Exception() != null)
{
    @Html.Exception().Message
}

3月20日添加生成jQuery错误样式:------------------------------------------------

public static class HandleExceptionHelper
{
    public static Exception Exception(this HtmlHelper htmlhelper)
    {
        var exception = htmlhelper.ViewContext.Controller.ViewData["Exception"] as Exception;
        return exception;
    }
 
    public static MvcHtmlString jQueryStyleError(this HtmlHelper htmlhelper)
    {
        var exception = Exception(htmlhelper);
 
        if (exception == null)
        {
            return null;
        }
 
        TagBuilder builder = new TagBuilder("div");
        builder.GenerateId("editordescription");
        builder.AddCssClass("ui-widget ui-state-error ui-corner-all");
        builder.InnerHtml = string.Format(@"<p><span class=""ui-icon ui-icon-alert"" style=""float: left; margin-right: .3em;""></span><strong>{0}: </strong>{1}</p>",
            Resx.Error, string.IsNullOrEmpty(exception.Message) ? Resx.UnknowErrorMessage : exception.Message);
 
        return new MvcHtmlString(builder.ToString(TagRenderMode.Normal));
    }
}

View应用如下:

@Html.jQueryStyleError()

效果如下:

ASP.NET MVC异常处理方案的更多相关文章

  1. ASP.NET MVC异常处理

    ASP.NET MVC异常处理方案 如何保留异常前填写表单的数据 ASP.NET MVC中的统一化自定义异常处理 MVC过滤器详解 MVC过滤器使用案例:统一处理异常顺道精简代码 ASP.NET MV ...

  2. 一个简单的ASP.NET MVC异常处理模块

    一.前言 异常处理是每个系统必不可少的一个重要部分,它可以让我们的程序在发生错误时友好地提示.记录错误信息,更重要的是不破坏正常的数据和影响系统运行.异常处理应该是一个横切点,所谓横切点就是各个部分都 ...

  3. ASP.NET mvc异常处理的方法

    第一种:全局异常处理 1.首先常见保存异常的类(就是将异常信息写入到文件中去) public class LogManager { private string logFilePath = strin ...

  4. ASP.NET MVC Anti-XSS方案

    1:Form提交模式 在使用Form提交时,MVC框架提供了一个默认的机制.如果数据中含有恶意字,则会自动转向出错页面.   2:Ajax+JSON提交模式. MVC框架未提供对于Json数据的Ant ...

  5. asp.net MVC 异常处理

    http://www.cnblogs.com/think8848/archive/2011/03/18/1987849.html http://www.cnblogs.com/snowdream/ar ...

  6. NET MVC异常处理模块

    一个简单的ASP.NET MVC异常处理模块   一.前言 异常处理是每个系统必不可少的一个重要部分,它可以让我们的程序在发生错误时友好地提示.记录错误信息,更重要的是不破坏正常的数据和影响系统运行. ...

  7. ASP.NET MVC 多语言方案

    前言: 好多年没写文章了,工作很忙,天天加班, 每天都相信不用多久,就会升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰,想想还有点小激动~~~~ 直到后来发生了邮箱事件,我竟然忘了给邮箱密 ...

  8. 七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL

    本节又带了一些常用的,却很难理解的问题,本节从文件上传功能的实现引出了线程使用,介绍了线程饥饿的解决方法,异常处理方法,了解RouteTable自定义路径 . 系列文章 七天学会ASP.NET MVC ...

  9. Asp.net Mvc 身份验证、异常处理、权限验证(拦截器)实现代码

    本问主要介绍asp.net的身份验证机制及asp.net MVC拦截器在项目中的运用.现在让我们来模拟一个简单的流程:用户登录>权限验证>异常处理 1.用户登录 验证用户是否登录成功步骤直 ...

随机推荐

  1. SQL实用札记【SQL Sever篇】

    目录 从表中去除重复行 逗号分隔字符串转数据表行 跨DB/Server执行SP[分布式事务] 在OpenQuery中执行带参数的SQL语句 从表中去除重复行数据 1. 如果有ID字段,就是具有唯一性的 ...

  2. Python2.7-weakref

    weakref 模块,允许创建对象的弱引用,被弱引用的对象其引用计数不变,对象的引用计数为0时就会被垃圾清理机制释放内存空间,此时对其的弱引用也会失效.在对象会被交叉引用,需要释放内存空间时常用. 模 ...

  3. C#可空类型(转载)

    在程序开发中,有时候需要值类型也为可空类型,比如,在数据库中,我们可以把一个日期Datetime设置为null. 在C# 2.0中就出现了可空类型,允许值类型也可以为空(null),可空类型的实现基于 ...

  4. 编译最新的SQLite 3.8.4.3为一个DLL

    SQLite是一个小型数据库.特别适合于client应用程序使用,它的众多优点就不多说了.有兴趣的去搜索. 话说使用吧. 我们要使用.就须要调用它.如今一步一步来. 第一步:上SQLite官网http ...

  5. Php的常见错误及错误分析

    我们在进行开发工作的时候,难免会遇到PHP的报错,解决这些错误,也是作为PHPer必须掌握的一种技能. 如果程序发生错误,我们能大致的分析出出现错误的原因,对于我们解决这戏错误会有很大的帮助. Not ...

  6. Flutter - 添加从左向右滑动,返回上一个页面

    很多App比如微信.IT之家等都支持从屏幕左侧向右滑动,来返回上一个页面. 很多iOS上的App也都支持. 那么这个神奇的手势滑动是怎么实现的呢? 其实非常简单,只需要添加一句话即可. platfor ...

  7. 20155218《网络对抗》Exp3 免杀原理与实践

    20155218<网络对抗>Exp3 免杀原理与实践 一.使用msf生成后门程序的检测 (1)将上周msf生成的后门文件放在virscan.org中进行扫描,截图如下: (2)使用msf时 ...

  8. 《Flask Web开发实战:入门、进阶与原理解析(李辉著 )》PDF+源代码

    一句话评价: 这可能是市面上(包括国外出版的)你能找到最好的讲Flask的书了 下载:链接: https://pan.baidu.com/s/1ioEfLc7Hc15jFpC-DmEYBA 提取码: ...

  9. lnmp如何实现伪静态,默认目录伪静态

    LNMP一键安装包一直是我小内存VPS的首选安装环境,因为它占用资源少,性能高.最新发布的lnmp0.7还增加了对LNMPA的支持,LNMPA使用Nginx作为前端服务能够更快更及时的静态页面.js. ...

  10. python 网络爬虫介绍

    一.网络爬虫相关概念 网络爬虫介绍 我们都知道,当前我们所处的时代是大数据的时代,在大数据时代,要进行数据分析,首先要有数据源,而学习爬虫,可以让我们获取更多的数据源,并且这些数据源可以按我们的目的进 ...