Использование ActionFilter трудно поддерживать , потому что всякий раз, когда мы выдаем ошибку, фильтр должен быть установлен в атрибуте. Что если мы забудем установить его? Одним из способов является получение OnException
на базовом контроллере. Вам необходимо определить BaseController
, полученный из Controller
, а все ваши контроллеры должны быть получены из BaseController
. Рекомендуется иметь базовый контроллер.
Обратите внимание, что при использовании Exception
код состояния ответа равен 500, поэтому нам нужно изменить его на 404 для Not Found и 401 для Unauthorized. Как я упоминал выше, используйте OnException
переопределения для BaseController
, чтобы избежать использования атрибута фильтра.
Новый MVC 3 также создает проблемы, возвращая пустой вид в браузер. Лучшее решение после некоторых исследований основано на моем ответе здесь Как вернуть представление для HttpNotFound () в ASP.Net MVC 3?
Для большего удобства я вставляю это здесь:
После некоторого изучения. Обходной путь для MVC 3 здесь заключается в извлечении всех HttpNotFoundResult
, HttpUnauthorizedResult
, HttpStatusCodeResult
классов и реализации new (переопределяя его) HttpNotFound
() в методе BaseController
.
Рекомендуется использовать базовый контроллер, чтобы у вас был «контроль» над всеми производными контроллерами.
Я создаю новый класс HttpStatusCodeResult
, не производный от ActionResult
, а от ViewResult
для визуализации представления или любого View
, который вы хотите, указав свойство ViewName
. Я следую исходному 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
, или создать новое NotFound.cshtml
, как я прокомментировал в коде, и вы можете определить модель представления для описания статуса и других объяснений.