如何在ASP中返回HttpNotFound()的视图。净MVC 3 ?

时间:2021-05-26 11:21:46

Is there a way to return the same view every time a HttpNotFoundResult is returned from a controller? How do you specify this view? I'm guessing configuring a 404 page in the web.config might work, but I wanted to know if there was a better way to handle this result.

是否有一种方法可以在从控制器返回HttpNotFoundResult时返回相同的视图?如何指定这个视图?我猜是在web上配置404页面。配置可能会工作,但是我想知道是否有更好的方法来处理这个结果。

Edit / Follow up:

编辑/跟进:

I ended up using the solution found in the second answer to this question with some slight tweaks for ASP.Net MVC 3 to handle my 404s: How can I properly handle 404s in ASP.Net MVC?

最后,我使用了这个问题的第二个答案,并对ASP做了一些微调。Net MVC 3处理我的404s:如何正确处理404s的ASP。净MVC吗?

6 个解决方案

#1


63  

HttpNotFoundResult doesn't render a view. It simply sets the status code to 404 and returns an empty result which is useful for things like AJAX but if you want a custom 404 error page you could throw new HttpException(404, "Not found") which will automatically render the configured view in web.config:

HttpNotFoundResult不呈现视图。它简单地将状态代码设置为404,并返回一个空结果,这对于像AJAX这样的事情非常有用,但是如果您想要一个自定义404错误页面,您可以抛出新的HttpException(404,“Not found”),它将自动呈现web.config中的配置视图:

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
   <error statusCode="404" redirect="/Http404.html" />
</customErrors>

#2


15  

This solution combines IResultFilter and IExceptionFilter to catch either thrown HttpException or returned HttpStatusCodeResult from within an action.

这个解决方案结合了IResultFilter和IExceptionFilter来捕获抛出的HttpException或在操作中返回HttpStatusCodeResult。

public class CustomViewForHttpStatusResultFilter: IResultFilter, IExceptionFilter
{
    string viewName;
    int statusCode;

    public CustomViewForHttpStatusResultFilter(HttpStatusCodeResult prototype, string viewName)
        : this(prototype.StatusCode, viewName) {
    }

    public CustomViewForHttpStatusResultFilter(int statusCode, string viewName) {
        this.viewName = viewName;
        this.statusCode = statusCode;
    }

    public void OnResultExecuted(ResultExecutedContext filterContext) {
        HttpStatusCodeResult httpStatusCodeResult = filterContext.Result as HttpStatusCodeResult;

        if (httpStatusCodeResult != null && httpStatusCodeResult.StatusCode == statusCode) {
            ExecuteCustomViewResult(filterContext.Controller.ControllerContext);

        }
    }

    public void OnResultExecuting(ResultExecutingContext filterContext) {
    }

    public void OnException(ExceptionContext filterContext) {
        HttpException httpException = filterContext.Exception as HttpException;

        if (httpException != null && httpException.GetHttpCode() == statusCode) {
            ExecuteCustomViewResult(filterContext.Controller.ControllerContext);
            // This causes ELMAH not to log exceptions, so commented out
            //filterContext.ExceptionHandled = true;
        }
    }

    void ExecuteCustomViewResult(ControllerContext controllerContext) {
        ViewResult viewResult = new ViewResult();
        viewResult.ViewName = viewName;
        viewResult.ViewData = controllerContext.Controller.ViewData;
        viewResult.TempData = controllerContext.Controller.TempData;
        viewResult.ExecuteResult(controllerContext);
        controllerContext.HttpContext.Response.TrySkipIisCustomErrors = true;            
    }
}

You can register this filter so, specifying either the http status code of the HttpException or the concrete HttpStatusCodeResult for which you want to display the custom view.

您可以注册这个过滤器,以便指定HttpException的http状态代码或您想要显示自定义视图的具体HttpStatusCodeResult。

GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(new HttpNotFoundResult(), "Error404"));
// alternate syntax
GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(404, "Error404"));

It handles exceptions and HttpStatusCodeResult thrown or returned within an action. It won't handle errors that occur before MVC selects a suitable action and controller like this common problems:

它处理在操作中抛出或返回的异常和HttpStatusCodeResult。它不会处理在MVC选择合适的动作和控制器之前发生的错误,比如这个常见的问题:

  • Unknown routes
  • 未知的路线
  • Unknown controllers
  • 未知的控制器
  • Unknown actions
  • 未知的操作

For handling these types of NotFound errors, combine this solution with other solutions to be found in *.

要处理这些类型的NotFound错误,请将此解决方案与*中可以找到的其他解决方案结合使用。

#3


14  

Useful info from @Darin Dimitrov that HttpNotFoundResult is actually returning empty result.

来自@Darin Dimitrov的有用信息:HttpNotFoundResult实际上返回空结果。

After some study. The workaround for MVC 3 here is to derive all HttpNotFoundResult, HttpUnauthorizedResult, HttpStatusCodeResult classes and implement new (overriding it) HttpNotFound() method in BaseController.

经过一些研究。这里MVC 3的解决方案是派生所有HttpNotFoundResult、HttpUnauthorizedResult、HttpStatusCodeResult类,并在BaseController中实现新的(重写它)HttpNotFound()方法。

It is best practise to use base Controller so you have 'control' over all derived Controllers.

最好的做法是使用基本控制器,这样您就可以对所有派生控制器进行“控制”。

I create new HttpStatusCodeResult class, not to derive from ActionResult but from ViewResult to render the view or any View you want by specifying the ViewName property. I follow the original HttpStatusCodeResult to set the HttpContext.Response.StatusCode and HttpContext.Response.StatusDescription but then base.ExecuteResult(context) will render the suitable view because again I derive from ViewResult. Simple enough is it? Hope this will be implemented in the MVC core.

我创建了新的HttpStatusCodeResult类,不是派生自ActionResult,而是通过指定ViewName属性来呈现视图或您想要的任何视图。我遵循原始的HttpStatusCodeResult来设置HttpContext.Response。StatusCode HttpContext.Response。接下来是base.ExecuteResult(上下文),它将呈现适当的视图,因为我同样是从ViewResult派生出来的。很简单是吗?希望这将在MVC核心实现。

See my BaseController bellow:

看到我BaseController波形:

using System.Web;
using System.Web.Mvc;

namespace YourNamespace.Controllers
{
    public class BaseController : Controller
    {
        public BaseController()
        {
            ViewBag.MetaDescription = Settings.metaDescription;
            ViewBag.MetaKeywords = Settings.metaKeywords;
        }

        protected new HttpNotFoundResult HttpNotFound(string statusDescription = null)
        {
            return new HttpNotFoundResult(statusDescription);
        }

        protected HttpUnauthorizedResult HttpUnauthorized(string statusDescription = null)
        {
            return new HttpUnauthorizedResult(statusDescription);
        }

        protected class HttpNotFoundResult : HttpStatusCodeResult
        {
            public HttpNotFoundResult() : this(null) { }

            public HttpNotFoundResult(string statusDescription) : base(404, statusDescription) { }

        }

        protected class HttpUnauthorizedResult : HttpStatusCodeResult
        {
            public HttpUnauthorizedResult(string statusDescription) : base(401, statusDescription) { }
        }

        protected class HttpStatusCodeResult : ViewResult
        {
            public int StatusCode { get; private set; }
            public string StatusDescription { get; private set; }

            public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { }

            public HttpStatusCodeResult(int statusCode, string statusDescription)
            {
                this.StatusCode = statusCode;
                this.StatusDescription = statusDescription;
            }

            public override void ExecuteResult(ControllerContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                context.HttpContext.Response.StatusCode = this.StatusCode;
                if (this.StatusDescription != null)
                {
                    context.HttpContext.Response.StatusDescription = this.StatusDescription;
                }
                // 1. Uncomment this to use the existing Error.ascx / Error.cshtml to view as an error or
                // 2. Uncomment this and change to any custom view and set the name here or simply
                // 3. (Recommended) Let it commented and the ViewName will be the current controller view action and on your view (or layout view even better) show the @ViewBag.Message to produce an inline message that tell the Not Found or Unauthorized
                //this.ViewName = "Error";
                this.ViewBag.Message = context.HttpContext.Response.StatusDescription;
                base.ExecuteResult(context);
            }
        }
    }
}

To use in your action like this:

在你的行动中使用如下:

public ActionResult Index()
{
    // Some processing
    if (...)
        return HttpNotFound();
    // Other processing
}

And in _Layout.cshtml (like master page)

_Layout。cshtml(主页)

<div class="content">
    @if (ViewBag.Message != null)
    {
        <div class="inlineMsg"><p>@ViewBag.Message</p></div>
    }
    @RenderBody()
</div>

Additionally you can use a custom view like Error.shtml or create new NotFound.cshtml like I commented in the code and you may define a view model for the status description and other explanations.

此外,您还可以使用自定义视图,比如Error。shtml或创建新的NotFound。就像我在代码中注释的cshtml一样,您可以为状态描述和其他解释定义一个视图模型。

#4


2  

protected override void HandleUnknownAction(string actionName)
{
    ViewBag.actionName  = actionName;
    View("Unknown").ExecuteResult(this.ControllerContext);
}

#5


0  

Here is true answer which allows fully customize of error page in single place. No need to modify web.confiog or create sophisticated classes and code. Works also in MVC 5.

这是一个真实的答案,允许在单个地方完全自定义错误页面。不需要修改网页。创建复杂的类和代码。也适用于MVC 5。

Add this code to controller:

将此代码添加到控制器:

        if (bad) {
            Response.Clear();
            Response.TrySkipIisCustomErrors = true;
            Response.Write(product + I(" Toodet pole"));
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            //Response.ContentType = "text/html; charset=utf-8";
            Response.End();
            return null;
        }

Based on http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

基于http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

#6


0  

Please follow this if you want httpnotfound Error in your controller

如果希望在控制器中出现httpnotfound错误,请遵循此命令

  public ActionResult Contact()
    {

        return HttpNotFound();
    }

#1


63  

HttpNotFoundResult doesn't render a view. It simply sets the status code to 404 and returns an empty result which is useful for things like AJAX but if you want a custom 404 error page you could throw new HttpException(404, "Not found") which will automatically render the configured view in web.config:

HttpNotFoundResult不呈现视图。它简单地将状态代码设置为404,并返回一个空结果,这对于像AJAX这样的事情非常有用,但是如果您想要一个自定义404错误页面,您可以抛出新的HttpException(404,“Not found”),它将自动呈现web.config中的配置视图:

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
   <error statusCode="404" redirect="/Http404.html" />
</customErrors>

#2


15  

This solution combines IResultFilter and IExceptionFilter to catch either thrown HttpException or returned HttpStatusCodeResult from within an action.

这个解决方案结合了IResultFilter和IExceptionFilter来捕获抛出的HttpException或在操作中返回HttpStatusCodeResult。

public class CustomViewForHttpStatusResultFilter: IResultFilter, IExceptionFilter
{
    string viewName;
    int statusCode;

    public CustomViewForHttpStatusResultFilter(HttpStatusCodeResult prototype, string viewName)
        : this(prototype.StatusCode, viewName) {
    }

    public CustomViewForHttpStatusResultFilter(int statusCode, string viewName) {
        this.viewName = viewName;
        this.statusCode = statusCode;
    }

    public void OnResultExecuted(ResultExecutedContext filterContext) {
        HttpStatusCodeResult httpStatusCodeResult = filterContext.Result as HttpStatusCodeResult;

        if (httpStatusCodeResult != null && httpStatusCodeResult.StatusCode == statusCode) {
            ExecuteCustomViewResult(filterContext.Controller.ControllerContext);

        }
    }

    public void OnResultExecuting(ResultExecutingContext filterContext) {
    }

    public void OnException(ExceptionContext filterContext) {
        HttpException httpException = filterContext.Exception as HttpException;

        if (httpException != null && httpException.GetHttpCode() == statusCode) {
            ExecuteCustomViewResult(filterContext.Controller.ControllerContext);
            // This causes ELMAH not to log exceptions, so commented out
            //filterContext.ExceptionHandled = true;
        }
    }

    void ExecuteCustomViewResult(ControllerContext controllerContext) {
        ViewResult viewResult = new ViewResult();
        viewResult.ViewName = viewName;
        viewResult.ViewData = controllerContext.Controller.ViewData;
        viewResult.TempData = controllerContext.Controller.TempData;
        viewResult.ExecuteResult(controllerContext);
        controllerContext.HttpContext.Response.TrySkipIisCustomErrors = true;            
    }
}

You can register this filter so, specifying either the http status code of the HttpException or the concrete HttpStatusCodeResult for which you want to display the custom view.

您可以注册这个过滤器,以便指定HttpException的http状态代码或您想要显示自定义视图的具体HttpStatusCodeResult。

GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(new HttpNotFoundResult(), "Error404"));
// alternate syntax
GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(404, "Error404"));

It handles exceptions and HttpStatusCodeResult thrown or returned within an action. It won't handle errors that occur before MVC selects a suitable action and controller like this common problems:

它处理在操作中抛出或返回的异常和HttpStatusCodeResult。它不会处理在MVC选择合适的动作和控制器之前发生的错误,比如这个常见的问题:

  • Unknown routes
  • 未知的路线
  • Unknown controllers
  • 未知的控制器
  • Unknown actions
  • 未知的操作

For handling these types of NotFound errors, combine this solution with other solutions to be found in *.

要处理这些类型的NotFound错误,请将此解决方案与*中可以找到的其他解决方案结合使用。

#3


14  

Useful info from @Darin Dimitrov that HttpNotFoundResult is actually returning empty result.

来自@Darin Dimitrov的有用信息:HttpNotFoundResult实际上返回空结果。

After some study. The workaround for MVC 3 here is to derive all HttpNotFoundResult, HttpUnauthorizedResult, HttpStatusCodeResult classes and implement new (overriding it) HttpNotFound() method in BaseController.

经过一些研究。这里MVC 3的解决方案是派生所有HttpNotFoundResult、HttpUnauthorizedResult、HttpStatusCodeResult类,并在BaseController中实现新的(重写它)HttpNotFound()方法。

It is best practise to use base Controller so you have 'control' over all derived Controllers.

最好的做法是使用基本控制器,这样您就可以对所有派生控制器进行“控制”。

I create new HttpStatusCodeResult class, not to derive from ActionResult but from ViewResult to render the view or any View you want by specifying the ViewName property. I follow the original HttpStatusCodeResult to set the HttpContext.Response.StatusCode and HttpContext.Response.StatusDescription but then base.ExecuteResult(context) will render the suitable view because again I derive from ViewResult. Simple enough is it? Hope this will be implemented in the MVC core.

我创建了新的HttpStatusCodeResult类,不是派生自ActionResult,而是通过指定ViewName属性来呈现视图或您想要的任何视图。我遵循原始的HttpStatusCodeResult来设置HttpContext.Response。StatusCode HttpContext.Response。接下来是base.ExecuteResult(上下文),它将呈现适当的视图,因为我同样是从ViewResult派生出来的。很简单是吗?希望这将在MVC核心实现。

See my BaseController bellow:

看到我BaseController波形:

using System.Web;
using System.Web.Mvc;

namespace YourNamespace.Controllers
{
    public class BaseController : Controller
    {
        public BaseController()
        {
            ViewBag.MetaDescription = Settings.metaDescription;
            ViewBag.MetaKeywords = Settings.metaKeywords;
        }

        protected new HttpNotFoundResult HttpNotFound(string statusDescription = null)
        {
            return new HttpNotFoundResult(statusDescription);
        }

        protected HttpUnauthorizedResult HttpUnauthorized(string statusDescription = null)
        {
            return new HttpUnauthorizedResult(statusDescription);
        }

        protected class HttpNotFoundResult : HttpStatusCodeResult
        {
            public HttpNotFoundResult() : this(null) { }

            public HttpNotFoundResult(string statusDescription) : base(404, statusDescription) { }

        }

        protected class HttpUnauthorizedResult : HttpStatusCodeResult
        {
            public HttpUnauthorizedResult(string statusDescription) : base(401, statusDescription) { }
        }

        protected class HttpStatusCodeResult : ViewResult
        {
            public int StatusCode { get; private set; }
            public string StatusDescription { get; private set; }

            public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { }

            public HttpStatusCodeResult(int statusCode, string statusDescription)
            {
                this.StatusCode = statusCode;
                this.StatusDescription = statusDescription;
            }

            public override void ExecuteResult(ControllerContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                context.HttpContext.Response.StatusCode = this.StatusCode;
                if (this.StatusDescription != null)
                {
                    context.HttpContext.Response.StatusDescription = this.StatusDescription;
                }
                // 1. Uncomment this to use the existing Error.ascx / Error.cshtml to view as an error or
                // 2. Uncomment this and change to any custom view and set the name here or simply
                // 3. (Recommended) Let it commented and the ViewName will be the current controller view action and on your view (or layout view even better) show the @ViewBag.Message to produce an inline message that tell the Not Found or Unauthorized
                //this.ViewName = "Error";
                this.ViewBag.Message = context.HttpContext.Response.StatusDescription;
                base.ExecuteResult(context);
            }
        }
    }
}

To use in your action like this:

在你的行动中使用如下:

public ActionResult Index()
{
    // Some processing
    if (...)
        return HttpNotFound();
    // Other processing
}

And in _Layout.cshtml (like master page)

_Layout。cshtml(主页)

<div class="content">
    @if (ViewBag.Message != null)
    {
        <div class="inlineMsg"><p>@ViewBag.Message</p></div>
    }
    @RenderBody()
</div>

Additionally you can use a custom view like Error.shtml or create new NotFound.cshtml like I commented in the code and you may define a view model for the status description and other explanations.

此外,您还可以使用自定义视图,比如Error。shtml或创建新的NotFound。就像我在代码中注释的cshtml一样,您可以为状态描述和其他解释定义一个视图模型。

#4


2  

protected override void HandleUnknownAction(string actionName)
{
    ViewBag.actionName  = actionName;
    View("Unknown").ExecuteResult(this.ControllerContext);
}

#5


0  

Here is true answer which allows fully customize of error page in single place. No need to modify web.confiog or create sophisticated classes and code. Works also in MVC 5.

这是一个真实的答案,允许在单个地方完全自定义错误页面。不需要修改网页。创建复杂的类和代码。也适用于MVC 5。

Add this code to controller:

将此代码添加到控制器:

        if (bad) {
            Response.Clear();
            Response.TrySkipIisCustomErrors = true;
            Response.Write(product + I(" Toodet pole"));
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            //Response.ContentType = "text/html; charset=utf-8";
            Response.End();
            return null;
        }

Based on http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

基于http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

#6


0  

Please follow this if you want httpnotfound Error in your controller

如果希望在控制器中出现httpnotfound错误,请遵循此命令

  public ActionResult Contact()
    {

        return HttpNotFound();
    }