当前位置:  开发笔记 > 后端 > 正文

ASP.NET MVC 404错误处理

如何解决《ASP.NETMVC404错误处理》经验,为你挑选了3个好方法。

我调查了很多关于如何在MVC妥善管理404 (具体MVC3) ,这一点,恕我直言,是最好的解决方案,我想出来的:

在global.asax中:

public class MvcApplication : HttpApplication
{
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }
}

ErrorsController:

public sealed class ErrorsController : Controller
{
    public ActionResult NotFound()
    {
        ActionResult result;

        object model = Request.Url.PathAndQuery;

        if (!Request.IsAjaxRequest())
            result = View(model);
        else
            result = PartialView("_NotFound", model);

        return result;
    }
}

编辑:

如果您正在使用IoC(例如AutoFac),则应使用以下命令创建控制器:

var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);

代替

IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));

(可选的)

说明:

我可以想到有6个场景,ASP.NET MVC3应用程序可以生成404s.

由ASP.NET生成:

场景1: URL与路由表中的路由不匹配.

由ASP.NET MVC生成:

场景2: URL匹配路由,但指定不存在的控制器.

场景3: URL匹配路由,但指定不存在的操作.

手动生成:

场景4:操作使用方法HttpNotFound()返回HttpNotFoundResult.

场景5:操作抛出HttpException,状态代码为404.

方案6:操作手动将Response.StatusCode属性修改为404.

目标

(A)向用户显示自定义404错误页面.

(B)维护客户端响应的404状态代码(对SEO特别重要).

(C)直接发送响应,不涉及302重定向.

解决方案尝试:自定义错误


    
        
    

此解决方案的问题:

不符合方案(1),(4),(6)中的目标(A).

不自动符合目标(B).必须手动编程.

不符合目标(C).

解决方案尝试:HTTP错误


    
        
        
    

此解决方案的问题:

仅适用于IIS 7+.

不符合方案(2),(3),(5)中的目标(A).

不自动符合目标(B).必须手动编程.

解决方案尝试:带有替换的HTTP错误


    
        
        
    

此解决方案的问题:

仅适用于IIS 7+.

不自动符合目标(B).必须手动编程.

它模糊了应用程序级别的http异常.例如,不能使用customErrors部分,System.Web.Mvc.HandleErrorAttribute等.它不仅可以显示通用错误页面.

解决方案尝试customErrors和HTTP错误


    
        
    


    
        
        
    

此解决方案的问题:

仅适用于IIS 7+.

不自动符合目标(B).必须手动编程.

不符合方案(2),(3),(5)中的目标(C).

在尝试创建自己的库之前,对此感到困扰的人们(请参阅http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html).但是之前的解决方案似乎涵盖了所有场景,而没有使用外部库的复杂性.



1> Marco..:

我调查了很多关于如何在MVC妥善管理404 (具体MVC3) ,这一点,恕我直言,是最好的解决方案,我想出来的:

在global.asax中:

public class MvcApplication : HttpApplication
{
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }
}

ErrorsController:

public sealed class ErrorsController : Controller
{
    public ActionResult NotFound()
    {
        ActionResult result;

        object model = Request.Url.PathAndQuery;

        if (!Request.IsAjaxRequest())
            result = View(model);
        else
            result = PartialView("_NotFound", model);

        return result;
    }
}

编辑:

如果您正在使用IoC(例如AutoFac),则应使用以下命令创建控制器:

var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);

代替

IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));

(可选的)

说明:

我可以想到有6个场景,ASP.NET MVC3应用程序可以生成404s.

由ASP.NET生成:

场景1: URL与路由表中的路由不匹配.

由ASP.NET MVC生成:

场景2: URL匹配路由,但指定不存在的控制器.

场景3: URL匹配路由,但指定不存在的操作.

手动生成:

场景4:操作使用方法HttpNotFound()返回HttpNotFoundResult.

场景5:操作抛出HttpException,状态代码为404.

方案6:操作手动将Response.StatusCode属性修改为404.

目标

(A)向用户显示自定义404错误页面.

(B)维护客户端响应的404状态代码(对SEO特别重要).

(C)直接发送响应,不涉及302重定向.

解决方案尝试:自定义错误


    
        
    

此解决方案的问题:

不符合方案(1),(4),(6)中的目标(A).

不自动符合目标(B).必须手动编程.

不符合目标(C).

解决方案尝试:HTTP错误


    
        
        
    

此解决方案的问题:

仅适用于IIS 7+.

不符合方案(2),(3),(5)中的目标(A).

不自动符合目标(B).必须手动编程.

解决方案尝试:带有替换的HTTP错误


    
        
        
    

此解决方案的问题:

仅适用于IIS 7+.

不自动符合目标(B).必须手动编程.

它模糊了应用程序级别的http异常.例如,不能使用customErrors部分,System.Web.Mvc.HandleErrorAttribute等.它不仅可以显示通用错误页面.

解决方案尝试customErrors和HTTP错误


    
        
    


    
        
        
    

此解决方案的问题:

仅适用于IIS 7+.

不自动符合目标(B).必须手动编程.

不符合方案(2),(3),(5)中的目标(C).

在尝试创建自己的库之前,对此感到困扰的人们(请参阅http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html).但是之前的解决方案似乎涵盖了所有场景,而没有使用外部库的复杂性.


@RickAndMSFT:`Response.Clear`有什么问题?抛出这样一个神秘的评论和博客文章,以"*不要使用那种方法*"结束,然后在要求澄清时保持沉默是没有用的.
我喜欢你的分析而不是你的解决方案:)等到请求结束的问题是某些请求上下文已被丢弃,例如会话状态.
@RickAndMSFT那篇文章没有提到Response.Clear,只提到了Response.Redirect.
嗨@PussInBoots.在MVC中,如果您的站点太大(很多控制器,模型和视图),您可以在区域中对它们进行逻辑分组.有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/ee671793(v=vs.100).aspx
@Marco,你的总结真的很棒,可能帮了很多人!我认为一个框架(ASP.NET/ASP.NET MVC)创建了如此多的混淆和复杂性来处理404/500错误是令人难以忍受的!比较其他Web框架:Yii,Rails,Django等,这部分在ASP.NET中真的很糟糕!
这是一篇很棒的文章,这是最好的解决方案,它涵盖了最常见的mvc设置中的所有细节.只是想补充一点,如果你有`runAllManagedModulesForAllRequests ="false"`,如果你关心性能就应该有,这个解决方案不适用于静态文件,因为它们(正确地)不会通过asp.net管道.此外,对于所有错误(不仅仅是404s),最好使用静态文件而不是路由,并将web.config属性作为备份,这样它仍然适用于asp.net启动中的错误,如路由配置.
您的解决方案不会捕获涉及文件扩展名的404错误(例如website.com/doesnt/exist.html),因为出于性能原因,托管管道不会被调用.
嗨,我正在收到状态码200。请参见。
使用MVC 5.1并转到未定义的控制器({“未找到路径'/ nonexantant / someaction'的控制器或未实现IController。“}),即使服务器最终将EndRequest中的响应状态代码仍为200返回带有404状态的默认404 IIS页面。这很令人不安,有什么想法吗?

2> Mike Chaliy..:

又一个解决方案.

添加ErrorControllers或静态页面以及404错误信息.

修改web.config(如果是控制器).


    
       
    

或者在静态页面的情况下


    
        
    

这将处理错过的路线和错过的行动.


使用``查看开发过程中的实际错误页面.
如果`返回HttpNotFound();`返回为来自控制器动作的`ActionResult`,则它不起作用.
这会导致302重定向,因此您不会保留原始HTTP代码.ASP.NET确实比控制HTTP堆栈更困难.
太好了!:) ErrorsController可以从与所有其他控制器相同的基础继承,因此可以访问某个功能.此外,Error404视图可以包含在master中,为用户提供网站其余部分的整体外观和感觉,而无需任何额外的工作.
此解决方案不起作用.对于"On"和"RemoteOnly"模式,我得到默认的404错误.

3> Yousi..:

Marco的回应是最佳解决方案.我需要控制我的错误处理,我的意思是真的控制它.当然,我已经扩展了一点解决方案并创建了一个管理所有内容的完整错误管理系统.我也在其他博客中读到了这个解决方案,大多数高级开发人员似乎都接受了这个解决方案.

这是我正在使用的最终代码:

protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            var exception = Server.GetLastError();
            var httpException = exception as HttpException;
            Response.Clear();
            Server.ClearError();
            var routeData = new RouteData();
            routeData.Values["controller"] = "ErrorManager";
            routeData.Values["action"] = "Fire404Error";
            routeData.Values["exception"] = exception;
            Response.StatusCode = 500;

            if (httpException != null)
            {
                Response.StatusCode = httpException.GetHttpCode();
                switch (Response.StatusCode)
                {
                    case 404:
                        routeData.Values["action"] = "Fire404Error";
                        break;
                }
            }
            // Avoid IIS7 getting in the middle
            Response.TrySkipIisCustomErrors = true;
            IController errormanagerController = new ErrorManagerController();
            HttpContextWrapper wrapper = new HttpContextWrapper(Context);
            var rc = new RequestContext(wrapper, routeData);
            errormanagerController.Execute(rc);
        }
    }

在我的ErrorManagerController里面:

        public void Fire404Error(HttpException exception)
    {
        //you can place any other error handling code here
        throw new PageNotFoundException("page or resource");
    }

现在,在我的Action中,我正在抛出我创建的自定义异常.我的Controller继承自我创建的自定义Controller Based类.创建自定义基本控制器以覆盖错误处理.这是我的自定义基本控制器类:

public class MyBasePageController : Controller
{
    protected override void OnException(ExceptionContext filterContext)
    {
        filterContext.GetType();
        filterContext.ExceptionHandled = true;
        this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
        base.OnException(filterContext);
    }
}

上面代码中的"ErrorManager"只是一个使用基于ExceptionContext的Model的视图

我的解决方案完美无缺,我可以在我的网站上处理任何错误,并根据任何异常类型显示不同的消息.


我不同意这是最佳解决方案。诸如此类的常见任务不应设置得那么复杂。Marcos的答案很不错,但您实际上不需要太多简单代码。
推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有