Пользовательские страницы ошибок на asp.net MVC3
Я разрабатываю базовый сайт MVC3, и я ищу решение для обработки ошибок и создания пользовательских представлений для каждого типа ошибок. Итак, представьте, что у меня есть контроллер "Error", где его основное действие - "Index" (общая страница ошибок), и у этого контроллера будет еще несколько действий для ошибок, которые могут появиться пользователю, например "Handle500" или "HandleActionNotFound".
Таким образом, каждая ошибка, которая может произойти на веб-сайте, может обрабатываться этим контроллером "Ошибка" (примеры: "Контроллер" или "Действие" не найдены, 500, 404, исключение dbException и т.д.).
Я использую файл Sitemap для определения пути к веб-сайту (а не маршрута).
Этот вопрос уже был дан ответ, это ответ Gweebz
Мой последний метод applicaiton_error следующий:
protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
try
{
var exception = Server.GetLastError();
Log.Logger.Error("unhandled exception: ", exception);
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
IController errorsController = new ErrorsController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
catch (Exception e)
{
//if Error controller failed for same reason, we will display static HTML error page
Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
Response.TransmitFile("~/error.html");
}
}
}
Ответы
Ответ 1
Вот пример того, как я обрабатываю пользовательские ошибки. Я определяю ErrorsController
с действиями, обрабатывающими разные ошибки HTTP:
public class ErrorsController : Controller
{
public ActionResult General(Exception exception)
{
return Content("General failure", "text/plain");
}
public ActionResult Http404()
{
return Content("Not found", "text/plain");
}
public ActionResult Http403()
{
return Content("Forbidden", "text/plain");
}
}
а затем я подписываюсь на Application_Error
в Global.asax
и вызываю этот контроллер:
protected void Application_Error()
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new ErrorsController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
Ответ 2
Вот еще статьи Как создать собственные страницы ошибок с MVC http://kitsula.com/Article/MVC-Custom-Error-Pages.
Ответ 3
Вы также можете сделать это в файле Web.Config. Вот пример, который работает в IIS 7.5.
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
<remove statusCode="502" subStatusCode="-1" />
<remove statusCode="501" subStatusCode="-1" />
<remove statusCode="412" subStatusCode="-1" />
<remove statusCode="406" subStatusCode="-1" />
<remove statusCode="405" subStatusCode="-1" />
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="403" subStatusCode="-1" />
<remove statusCode="401" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
<error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
<error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
<error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
<error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
<error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
<error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
<error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
<error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
Ответ 4
Я вижу, что вы добавили значение конфигурации для EnableCustomErrorPage
, и вы также проверяете IsDebuggingEnabled
, чтобы определить, следует ли запускать обработку ошибок.
Поскольку в ASP.NET уже существует <customErrors/>
, то это проще всего сказать:
protected void Application_Error()
{
if (HttpContext.Current == null)
{
// errors in Application_Start will end up here
}
else if (HttpContext.Current.IsCustomErrorEnabled)
{
// custom exception handling
}
}
Затем в конфиге вы положили бы <customErrors mode="RemoteOnly" />
, который можно безопасно развернуть, и когда вам нужно проверить свою страницу с ошибкой, вы должны установить ее на <customErrors mode="On" />
, чтобы вы могли убедиться, что она работает.
Обратите внимание, что вам также нужно проверить, является ли HttpContext.Current
нулевым, поскольку исключение в Application_Start
будет по-прежнему использоваться для этого метода, хотя активного контекста не будет.
Ответ 5
Вы можете отобразить удобную страницу с ошибкой с правильным кодом состояния http, внедряя Jeff Atwood "Пользовательский модуль обработки исключений" с небольшой модификацией для кода статуса http. Он работает без каких-либо переадресаций. Хотя код с 2004 года (!), Он хорошо работает с MVC. Он может быть полностью сконфигурирован в вашем web.config, без каких-либо изменений исходного кода проекта MVC.
Модификация, необходимая для возврата исходного статуса HTTP, а не статуса 200
, описана в этой связанной теме форума.
В принципе, в Handler.vb вы можете добавить что-то вроде:
' In the header...
Private _exHttpEx As HttpException = Nothing
' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
_exHttpEx = CType(ex, HttpException)
HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If
Ответ 6
Я использую MVC 4.5, и у меня возникли проблемы с решением Darin. Примечание. Решение Darin превосходно, и я использовал его для решения моего решения.
Здесь мое модифицированное решение:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();
Response.Clear();
Server.ClearError();
if (httpException != null)
{
var httpContext = HttpContext.Current;
httpContext.RewritePath("/Errors/InternalError", false);
// MVC 3 running on IIS 7+
if (HttpRuntime.UsingIntegratedPipeline)
{
switch (Response.StatusCode)
{
case 403:
httpContext.Server.TransferRequest("/Errors/Http403", true);
break;
case 404:
httpContext.Server.TransferRequest("/Errors/Http404", true);
break;
default:
httpContext.Server.TransferRequest("/Errors/InternalError", true);
break;
}
}
else
{
switch (Response.StatusCode)
{
case 403:
httpContext.RewritePath(string.Format("/Errors/Http403", true));
break;
case 404:
httpContext.RewritePath(string.Format("/Errors/Http404", true));
break;
default:
httpContext.RewritePath(string.Format("/Errors/InternalError", true));
break;
}
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(httpContext);
}
}
}