如何在ASP.Net MVC 3中返回HttpNotFound()的视图?
有没有办法每次从控制器返回HttpNotFoundResult时返回相同的视图? 你如何指定这个视图? 我猜configurationweb.config中的404页面可能工作,但我想知道是否有更好的方法来处理这个结果。
编辑/跟进:
我结束了对这个问题的第二个答案中find的解决scheme,稍微调整了ASP.Net MVC 3来处理我的404: 我怎样才能正确处理ASP.Net MVC中的404?
HttpNotFoundResult
不会呈现视图。 它只是将状态码设置为404,并返回一个空的结果,这对于像AJAX这样的东西很有用,但是如果你想要一个自定义的404错误页面,你可以throw new HttpException(404, "Not found")
, web.config中:
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite"> <error statusCode="404" redirect="/Http404.html" /> </customErrors>
这个解决scheme结合了IResultFilter和IExceptionFilter来捕获抛出的HttpException或者在一个action中返回的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; } }
你可以注册这个filter,指定HttpException的http状态码或者你不想显示自定义视图的具体的HttpStatusCodeResult。
GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(new HttpNotFoundResult(), "Error404")); // alternate syntax GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(404, "Error404"));
它处理在动作中抛出或返回的exception和HttpStatusCodeResult。 它不会处理MVCselect合适的操作和控制器之前发生的错误,如常见的问题:
- 未知的路线
- 未知的控制器
- 未知的行为
为了处理这些types的NotFound错误,请将此解决scheme与其他解决scheme结合使用,以便在stackoverflow中find。
@Darin Dimitrov的有用信息, HttpNotFoundResult
实际上是返回空的结果。
经过一番研究。 MVC 3的解决方法是派生所有HttpNotFoundResult
, HttpNotFoundResult
, HttpUnauthorizedResult
类并在BaseController
实现新的 (覆盖它) HttpNotFound
()方法。
使用基本控制器是最好的做法,因此您可以对所有派生的控制器进行“控制”。
我创build了新的HttpStatusCodeResult
类,不是从ActionResult
派生,而是从ViewResult
派生来通过指定ViewName
属性来呈现视图或任何View
。 我按照原来的HttpStatusCodeResult
来设置HttpContext.Response.StatusCode
和HttpContext.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
这样的自定义视图,或者像我在代码中评论的那样创build新的NotFound.cshtml
,并且可以为状态描述和其他解释定义视图模型。
protected override void HandleUnknownAction(string actionName) { ViewBag.actionName = actionName; View("Unknown").ExecuteResult(this.ControllerContext); }
这是真正的答案,允许在一个地方完全自定义错误页面。 无需修改web.confiog或创build复杂的类和代码。 也在MVC 5中工作。
将此代码添加到控制器:
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; }
基于http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages
如果你想在你的控制器中发现httpnotfound错误,请遵循这个步骤
public ActionResult Contact() { return HttpNotFound(); }