从ASP.NET MVC操作发送HTTP 404响应的正确方式是什么?
如果给定路线: {FeedName}/{ItemPermalink} ex:/Blog/Hello World 如果该项目不存在,我想返回404。在ASP.NET MVC中,正确的方法是什么?从臀部拍摄(牛仔编码;-),我建议如下:从ASP.NET MVC操作发送HTTP 404响应的正确方式是什么?,asp.net,asp.net-mvc,http-status-code-404,Asp.net,Asp.net Mvc,Http Status Code 404,如果给定路线: {FeedName}/{ItemPermalink} ex:/Blog/Hello World 如果该项目不存在,我想返回404。在ASP.NET MVC中,正确的方法是什么?从臀部拍摄(牛仔编码;-),我建议如下: throw new HttpException(404, "Are you sure you're in the right place?"); public ActionResult Index() { // Some processing if
throw new HttpException(404, "Are you sure you're in the right place?");
public ActionResult Index()
{
// Some processing
if (...)
return HttpNotFound();
// Other processing
}
控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
return new HttpNotFoundResult("This doesn't exist");
}
}
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 :)
HttpNotFoundResult:
public class HomeController : Controller
{
public ActionResult Index()
{
return new HttpNotFoundResult("This doesn't exist");
}
}
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 :)
使用系统;
Net系统;
使用System.Web;
使用System.Web.Mvc;
名称空间YourNamespaceHere
{
///它的一个实现抛出了一个错误。
公共类HttpNotFoundResult:ActionResult
{
///使用指定的初始化的新实例。
///
公共HttpNotFoundResult(字符串消息)
{
this.Message=消息;
}
///使用空消息初始化的新实例。
公共HttpNotFoundResult()
:this(String.Empty){}
///获取或设置将传递给抛出方的消息。
公共字符串消息{get;set;}
///覆盖基本功能以引发错误。
公共覆盖无效ExecuteSult(ControllerContext上下文)
{
抛出新的HttpException((Int32)HttpStatusCode.NotFound,this.Message);
}
}
}
//埃里克·范·布拉克尔,丹尼尔·谢弗编辑:)
使用这种方法,您可以遵守框架标准。那里已经有一个HttpUnauthorizedResult,因此这将在以后维护代码的其他开发人员(你知道,知道你住在哪里的神经病)眼中简单地扩展框架
您可以使用reflector查看组件,以了解如何实现HttpUnauthorizedResult,因为我不知道这种方法是否遗漏了任何内容(它似乎太简单了)
我刚才确实使用reflector查看了HttpUnauthorizedResult。似乎他们正在将响应的状态码设置为0x191(401)。虽然这适用于401,但使用404作为新值,我在Firefox中似乎只得到了一个空白页。Internet Explorer显示默认的404(不是ASP.NET版本)。使用webdeveloper工具栏,我检查了FF中的标题,它确实显示了404NotFound响应。可能只是我在FF中的错误配置
尽管如此,我认为杰夫的方法是接吻的一个很好的例子。如果您真的不需要这个示例中的详细信息,那么他的方法也可以很好地工作。我们就是这样做的;此代码位于
BaseController
/// <summary>
/// returns our standard page not found view
/// </summary>
protected ViewResult PageNotFound()
{
Response.StatusCode = 404;
return View("PageNotFound");
}
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
};
}
}
}
请注意,从MVC3开始,您可以使用
HttpStatusCodeResult
使用ActionFilter很难维护,因为每当我们抛出错误时,都需要在属性中设置过滤器。如果我们忘了设定呢?一种方法是在基本控制器上导出OnException
。您需要定义从Controller
派生的BaseController
,并且所有控制器都必须从BaseController
派生。最好有一个基地控制器
注意:如果使用Exception
响应状态代码为500,那么我们需要将其更改为404(未找到)和401(未授权)。正如我上面提到的,在BaseController
上使用OnException
覆盖以避免使用filter属性
新的MVC 3还通过将空视图返回到浏览器而使问题更加棘手。经过一些研究后,最好的解决方案是基于我的回答
为了更方便,我将其粘贴在此处:
经过一些研究。MVC 3的解决方法是在
BaseController
中派生所有HttpNotFoundResult
、HttpUnauthorizedResult
、HttpStatusCodeResult
类,并实现新的(覆盖它)HttpNotFound
()方法
最好使用基本控制器,这样您就可以“控制”所有派生控制器
我创建新的HttpStatusCodeResult
类,不是从ActionResult
派生,而是从ViewResult
派生,通过指定ViewName
属性来呈现视图或任何所需的视图。我按照原始的HttpStatusCodeResult
设置HttpContext.Response.StatusCode
和HttpContext.Response.StatusDescription
,但是base.ExecuteResult(context)
将呈现合适的视图,因为我再次从ViewResult
派生。够简单吗?希望这将在MVC核心中实现
请参见下面的myBaseController
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中(如母版页)
@如果(ViewBag.Message!=null)
{
@查看包。留言
}
@RenderBody()
此外,您可以使用自定义视图,如Error.shtml
或创建新的NotFound.cshtml
,如我在代码中的注释,您可以为状态描述和其他解释定义一个视图模型。谢谢您提出这个问题。这是我的标准项目补充:DYeah,我也注意到了枚举。正如我所说,这只是一个粗略的例子,请随意改进。这毕竟应该是一个知识库;-)我想我有点过火了。。。享受:DFWIW,杰夫的例子也要求你