如何在ASP.NET MVC中正确处理404?

 2023-02-17    390  

问题描述

我正在使用RC2

使用URL路由:

如何在ASP.NET MVC中正确处理404?

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

步骤1:有404-误差逻辑的共同位置

这是可维护性的好主意.使用 errorcontroller 未来改进您的精心设计的404页面可以轻松适应.另外,确保您的响应具有404代码!

public class ErrorController : MyController
{
    #region Http404

    public ActionResult Http404(string url)
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        var model = new NotFoundViewModel();
        // If the url is relative ('NotFound' route) then replace with Requested path
        model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
            Request.Url.OriginalString : url;
        // Dont get the user stuck in a 'retry loop' by
        // allowing the Referrer to be the same as the Request
        model.ReferrerUrl = Request.UrlReferrer != null &&
            Request.UrlReferrer.OriginalString != model.RequestedUrl ?
            Request.UrlReferrer.OriginalString : null;

        // TODO: insert ILogger here

        return View("NotFound", model);
    }
    public class NotFoundViewModel
    {
        public string RequestedUrl { get; set; }
        public string ReferrerUrl { get; set; }
    }

    #endregion
}

步骤2:使用基本控制器类,以便您可以轻松调用自定义404操作并汇总HandleUnknownAction

404在ASP.NET MVC中需要在许多地方捕获.第一个是HandleUnknownAction.

InvokeHttp404方法为重新路由ErrorController和我们的新Http404动作创造了一个共同的位置.想想 dry !

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

步骤3:使用控制器工厂中的依赖注入并汇合404 HTTPEXCEPTIONS

喜欢这样(不必是结构图):

mvc1.0示例:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }
}

mvc2.0示例:

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == 404)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }

我认为最好捕获到更接近其起源的错误.这就是为什么我更喜欢上面的Application_Error处理程序.

这是捕获404s的第二位.

步骤4:添加一个不符合路由到Global.asax的URL,该URL无法解析到您的应用程序

此路线应指向我们的Http404动作.请注意,url参数将是相对URL,因为路由引擎在此处剥离了域部分?这就是为什么我们在步骤1中拥有所有条件URL逻辑的原因.

routes.MapRoute("NotFound", "{*url}", 
            new { controller = "Error", action = "Http404" });

这是在MVC应用程序中捕获404秒的第三个也是最后一个,您不会调用自己.如果您在这里没有捕捉无与伦比的路线,那么MVC将把问题传递到asp.net(global.asax),并且在这种情况下您真的不想要它.

步骤5:最后,当您的应用找不到某些内容

时调用404

当将不良ID提交给我的贷款控制器时(源自MyController):

//
    // GET: /Detail/ID

    public ActionResult Detail(int ID)
    {
        Loan loan = this._svc.GetLoans().WithID(ID);
        if (loan == null)
            return this.InvokeHttp404(HttpContext);
        else
            return View(loan);
    }

,如果所有这些都可以在更少的代码中添加到更少的地方,但是我认为该解决方案更可维护,更可维护,更具测试性和务实性.

感谢到目前为止的反馈.我很想得到更多.

注意:这是从我的原始答案中大量编辑的,但是目的/要求是相同的 – 这就是为什么我没有添加新答案

其他推荐答案

ASP.NET MVC不太支持自定义404页.自定义控制器工厂,接收路线,带有HandleUnknownAction的基本控制器类-Argh!

iis自定义错误页面到目前为止是更好的选择:

web.config

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" />
    <error statusCode="404" responseMode="ExecuteURL" path="/Error/PageNotFound" />
  </httpErrors>
</system.webServer>

errorcontroller

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View();
    }
}

示例项目

  • test404 on Github
  • 实时网站

以上所述是小编给大家介绍的如何在ASP.NET MVC中正确处理404?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/34172.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。