什么是到从ASP.NET MVC操作的HTTP 404响应的正确方法?什么是到从ASP.NET MV

2019-05-13 08:48发布

如果给出的路线:

{FeedName} / {ItemPermalink}

例如:/博客/您好,世界

如果该项目不存在,我想回到404。什么是ASP.NET MVC这样做的正确方法?

Answer 1:

从臀部(牛仔编码;-))拍摄,我建议是这样的:

控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return new HttpNotFoundResult("This doesn't exist");
    }
}

HttpNotFoundResult:

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

namespace YourNamespaceHere
{
    /// <summary>An implementation of <see cref="ActionResult" /> that throws an <see cref="HttpException" />.</summary>
    public class HttpNotFoundResult : ActionResult
    {
        /// <summary>Initializes a new instance of <see cref="HttpNotFoundResult" /> with the specified <paramref name="message"/>.</summary>
        /// <param name="message"></param>
        public HttpNotFoundResult(String message)
        {
            this.Message = message;
        }

        /// <summary>Initializes a new instance of <see cref="HttpNotFoundResult" /> with an empty message.</summary>
        public HttpNotFoundResult()
            : this(String.Empty) { }

        /// <summary>Gets or sets the message that will be passed to the thrown <see cref="HttpException" />.</summary>
        public String Message { get; set; }

        /// <summary>Overrides the base <see cref="ActionResult.ExecuteResult" /> functionality to throw an <see cref="HttpException" />.</summary>
        public override void ExecuteResult(ControllerContext context)
        {
            throw new HttpException((Int32)HttpStatusCode.NotFound, this.Message);
        }
    }
}
// By Erik van Brakel, with edits from Daniel Schaffer :)

使用这种方法您必须遵守的框架标准。 已经有在那里HttpUnauthorizedResult,所以这只会在另一个开发人员眼中扩展框架维护你的代码以后(你知道,谁知道你住在哪里的心理)。

你可以使用反射来看一看到组件看到HttpUnauthorizedResult是如何实现的,因为我不知道这个方法忽略任何东西(它似乎太简单了差不多)。


我没有使用反射来看一看在HttpUnauthorizedResult刚才。 似乎他们设置的响应0x191(401)中的StatusCode。 虽然这适用于401,使用404作为新的价值,我似乎在Firefox中越来越只是一个空白页。 互联网资源管理器显示一个默认404虽然(而不是ASP.NET版本)。 使用webdeveloper工具栏我检查在FF头,其确实表现出404未找到响应。 可以简单的东西我在FF配置错误。


这是说,我认为杰夫的做法是KISS的一个很好的例子。 如果你并不真的需要这个样本中的冗长,他的方法能正常工作为好。



Answer 2:

我们做它像这样; 这段代码中发现的BaseController

/// <summary>
/// returns our standard page not found view
/// </summary>
protected ViewResult PageNotFound()
{
    Response.StatusCode = 404;
    return View("PageNotFound");
}

所谓像这样

public ActionResult ShowUserDetails(int? id)
{        
    // make sure we have a valid ID
    if (!id.HasValue) return PageNotFound();


Answer 3:

throw new HttpException(404, "Are you sure you're in the right place?");


Answer 4:

该HttpNotFoundResult是一个伟大的第一步,我在用。 返回的HttpNotFoundResult好。 接下来的问题是,下一步是什么?

我创建了一个名为HandleNotFoundAttribute一个动作过滤器则显示404错误页面。 由于它返回一个视图,您可以创建每个控制器一个专用的404视图,或者让是使用默认共享404视图。 因为框架投用的404状态码的HttpException这甚至可以被称为当控制器没有指定的操作存在。

public class HandleNotFoundAttribute : ActionFilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        var httpException = filterContext.Exception.GetBaseException() as HttpException;
        if (httpException != null && httpException.GetHttpCode() == (int)HttpStatusCode.NotFound)
        {
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; // Prevents IIS from intercepting the error and displaying its own content.
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.StatusCode = (int) HttpStatusCode.NotFound;
            filterContext.Result = new ViewResult
                                        {
                                            ViewName = "404",
                                            ViewData = filterContext.Controller.ViewData,
                                            TempData = filterContext.Controller.TempData
                                        };
        }
    }
}


Answer 5:

注意,MVC3的,你可以只使用HttpStatusCodeResult



Answer 6:

使用ActionFilter因为每当我们抛出一个错误的过滤器需要在属性设置是很难维持的 。 如果我们忘了设置什么呢? 一种方法是获得OnException基地控制器上。 您需要定义一个BaseController源自Controller和所有的控制器必须从派生BaseController 。 它是有一个基本控制器的最佳做法。

请注意,如果使用Exception响应状态代码是500,所以我们需要将其更改为404未找到和401对未经授权的。 就像我上面提到,使用OnException上覆盖BaseController避免使用过滤属性。

新的MVC 3也使通过返回一个空视图到浏览器更多的麻烦。 经过一番研究,最好的解决办法是基于我的答案在这里如何返回在ASP.Net MVC 3 HttpNotFound视图()?

为了让更多的舒适我在这里贴吧:


一些研究之后。 这里MVC 3的解决方法是获得所有HttpNotFoundResultHttpUnauthorizedResultHttpStatusCodeResult类和实施 (覆盖它) HttpNotFound ()方法BaseController

它是使用基本控制器,所以你必须对所有衍生控制器“控制”的最佳实践。

我创造新的HttpStatusCodeResult类,而不是从派生ActionResult但是从ViewResult渲染视图或View您想要通过指定ViewName属性。 我按照原来的HttpStatusCodeResult设置HttpContext.Response.StatusCodeHttpContext.Response.StatusDescription但随后base.ExecuteResult(context) ,因为我再次从派生将呈现适当的视图ViewResult 。 是不是很简单呢? 希望这将在MVC核心实现。

见我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);
            }
        }
    }
}

要在你的行动像这样使用:

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

而在_Layout.cshtml(母版页)

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

此外,您可以像使用自定义视图Error.shtml或创建新的NotFound.cshtml就像我在代码注释,你可以定义为状态说明和其他的解释视图模型。



文章来源: What is the proper way to send an HTTP 404 response from an ASP.NET MVC action?