zoukankan      html  css  js  c++  java
  • ASP.NET MVC2 异常处理机制中令人费解的HTTP 500错误

    ASP.NET MVC2 异常处理机制中令人费解的HTTP 500错误

    Visual Studio 2010 BETA2所集成之ASP.NET MVC应用程序中,可以使用HandleErrorAttribute来捕获并处理异常。

    但在默认情况下,用于显示异常的视图(Error.aspx)必须应用母版页(Site.Master),否则,如果尝试使用一个普通的视图来显示ASP.NET MVC应用程序异常信息,会报告“HTTP 500内部服务器错误”

           异常信息显示视图必须应用母版页,这是一个很让人郁闷的限制。

           为什么会有这个限制?

           使用Reflector反汇编HandleErrorAttributeOnException()方法,此方法将会在控制器中的Action方法有异常抛出时被ASP.NET MVC自动调用:

    public virtual void OnException(ExceptionContext filterContext)

    {

       //……代码略

           //生成用于显示异常信息的ViewResult

        filterContext.Result = new ViewResult { ViewName = this.View,

        MasterName = this.Master, ViewData = new    ViewDataDictionary<HandleErrorInfo>(model),

        TempData = filterContext.Controller.TempData };

        filterContext.ExceptionHandled = true;

        filterContext.HttpContext.Response.Clear();

        filterContext.HttpContext.Response.StatusCode = 500;

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

                }

        }

           可以看到,在生成用于显示异常信息的ViewResult之后,设置filterContextExceptionHandled=true,这将通知后继的异常捕获过滤器(如果有的话):本应用程序抛出的异常已经被处理过了,其他的人可以不用理会这个异常了。

           比较令人费解的是紧接着后面有3句代码引发了HTTP 500错误。

           经测试发现,如果ViewResult实例化的视图对象应用了母版页时,ASP.NET MVC会“吃掉”这一HTTP 500错误。

           然而,如果要实例化的视图对象是独立的,上述3句代码就“真”的引发了HTTP 500错误

           ASP.NET MVC的开发者为什么要加入这3句代码?笔者百思不得其解。

           尽管不知道原因,但我们可以通过编写一个自定义异常处理类来“屏蔽”掉上述3句引发麻烦的代码。其思路是这样的:

           HandleErrorAttribute派生一个自定义类MyErrorHandleAttribute,重写其基类的OnException方法。然后,给其添加一个bool类型的UseMasterPage属性,当其为false时,跳过上面3句引发麻烦的代码。

           MyErrorHandleAttribute的使用方法与HandleErrorAttribute一模一样,只是多了一个UseMasterPage属性:

    [MyErrorHandle(ExceptionType=typeof(NullReferenceException),

            View="ShowErrorUseViewPage",UseMasterPage=false)]

        [MyErrorHandle(ExceptionType=typeof(ApplicationException),

            View = "ShowErrorUseMasterPage",UseMasterPage=true)]

        public class HomeController : Controller

        {

            public ActionResult Index()

            {

                return View();

            }

            public ActionResult ThrowNullReferenceException()

            {

                throw new NullReferenceException();

            }

             public ActionResult ThrowApplicationException()

            {

                throw new ApplicationException();

            }

    }

     

    其中ShowErrorUseViewPage.aspx是普通视图,没有应用母版。

    以下是MyErrorHandleAttribute类的代码:

     

    public class MyErrorHandle : HandleErrorAttribute

    {

        public bool UseMasterPage

        {

            get;

            set;

        }

      

      public override void OnException(ExceptionContext filterContext)

        {

            if (filterContext == null)

            {

                throw new ArgumentNullException("filterContext");

            }

            if (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled)

            {

                Exception innerException = filterContext.Exception;

                if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException))

                {

                    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 = this.View, MasterName = this.Master, ViewData = new ViewDataDictionary<HandleErrorInfo>(model), TempData = filterContext.Controller.TempData };

                    filterContext.ExceptionHandled = true;

                    if (UseMasterPage)

                    {

                        filterContext.HttpContext.Response.Clear();

                        filterContext.HttpContext.Response.StatusCode = 500;

                        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

                    }

                }

            }      

        }

    }

     

    除了加方框的代码,其余部分都是原样复制于Reflector反汇编出来的代码。

    将保存了上述代码的“MyErrorHandleAttribute.cs”文件添加到ASP.NET MVC项目中,就可以在控制器中使用此自定义的异常处理类了。

    在以下环境中MyErrorHandleAttribute均工作正常:

    1)使用VS2010 BETA2开发和调试ASP.NET MVC2项目:

    2)将ASP.NET MVC2项目发布到IIS 7.5(应用ASP.NET 4.0集成模式)上以HTTP方式访问。

           需要指出的是,在笔者的测试中,发现现有版本的HandleErrorAttribute并非始终不能使用独立的视图对象,当使用VS2010 BETA2开发时,HTTP 500错误有时会发生有时又不会发生,实在令人费解。

           我想,这是不是ASP.NET MVC2当前版本的一个BUG

    也许等到VS2010正式版时,ASP.NET MVC开发小组的工程师会解决这一问题。

  • 相关阅读:
    《MySQL必知必会》第六章:过滤数据
    《MySQL必知必会》第七章:数据过滤
    《MySQL必知必会》第五章:排序检索数据
    Java高级特性:clone()方法
    Java基础知识详解:abstract修饰符
    Java虚拟机:虚拟机内存区域和内存溢出异常
    Java虚拟机:源码到机器码
    Java虚拟机:本地方法栈与Native方法
    [LeetCode] 1481. Least Number of Unique Integers after K Removals
    [LeetCode] 331. Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/bitfan/p/1621246.html
Copyright © 2011-2022 走看看