Обработка ошибок ASP.NET MVC 6 на основе кода состояния HTTP
Я хочу отображать разные сообщения об ошибках для каждого кода состояния, например:
- 400 Bad Request
- 403 Запрещено
- 500 Внутренняя ошибка сервера
- 404 Не найдено
- 401 Несанкционированный
Как я могу добиться этого в новых приложениях ASP.NET MVC 6? Могу ли я сделать это, используя встроенный метод UseErrorHandler?
application.UseErrorHandler("/error");
Кроме того, я заметил, что даже с вышеупомянутым обработчиком, введя несуществующий URL, например. /this -page-does-not-exist, вызывает уристую страницу ошибок 404 Not Found из IIS. Как это можно также обрабатывать?
В MVC 5 нам пришлось использовать раздел system.web customerrors для ASP.NET и раздела system.webServer httpErrors в файле web.config, но было трудно работать с громоздким, с очень странным поведением. Может ли MVC 6 сделать это намного проще?
Ответы
Ответ 1
Для этого вы можете использовать StatusCodePagesMiddleware
. Ниже приведен пример:
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseStatusCodePagesWithReExecute("/StatusCodes/StatusCode{0}");
app.UseMvcWithDefaultRoute();
Контроллер, который обрабатывает запросы кода состояния:
public class StatusCodesController : Controller
{
public IActionResult StatusCode404()
{
return View(viewName: "NotFound"); // you have a view called NotFound.cshtml
}
... more actions here to handle other status codes
}
Некоторые примечания:
- Проверьте другие методы расширения, например
UseStatusCodePagesWithRedirects
и UseStatusCodePages
для других возможностей.
- Я попытался иметь StatusCode в качестве строки запроса в моем примере, но выглядит так:
промежуточное ПО не обрабатывает строки запросов, но вы можете взглянуть на
этот код и исправить эту проблему.
Ответ 2
Как я могу добиться этого в новых приложениях ASP.NET MVC 6? Могу ли я это сделать, используя встроенный метод UseErrorHandler?
Быстрый ответ: Не в элегантном стиле.
Объяснение/Альтернатива: Чтобы начать сначала, посмотрите, что действительно делает метод UseErrorHandler
: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerExtensions.cs#L25, который добавляет следующее промежуточное ПО: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerMiddleware.cs Примечание строки 29-78 (метод вызова)
Метод invoke выполняется всякий раз, когда приходит запрос (контролируется местоположением вашего application.UseErrorHandler("...")
в вашем Startup.cs
). Таким образом, UseErrorHandler
- это прославленный способ добавления специального промежуточного программного обеспечения: middleware = component, который может действовать на HTTP-запрос.
Теперь с этим фоном, если мы хотим добавить наше собственное промежуточное ПО для ошибок, которое будет отличаться от запросов. Мы могли бы сделать это, добавив аналогичное промежуточное программное обеспечение, подобное стандарту ErrorHandlerMiddleware
, изменив эти строки: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerMiddleware.cs#L48-L51. При таком подходе мы могли бы контролировать перенаправить путь на основе кода состояния.
В MVC 5 нам нужно было использовать раздел system.web customerrors для ASP.NET и раздел system.webServer httpErrors в файле web.config, но было трудно работать с громоздким, с большим количеством очень странного поведения, Может ли MVC 6 сделать это намного проще?
Ответ: Он уверен, что делает:). Как и вышеприведенный ответ, исправление заключается в добавлении промежуточного программного обеспечения. Там есть ярлык для добавления простого промежуточного программного обеспечения через IApplicationBuilder
в Startup.cs
; в конце вашего метода Configure
вы можете добавить следующее:
app.Run(async (context) =>
{
await context.Response.WriteAsync("Could not handle the request.");
// Nothing else will run after this middleware.
});
Это будет работать, потому что это означает, что вы достигли конца вашего HTTP-конвейера без обработки запроса (поскольку он в конце вашего метода Configure
в Startup.cs
). Если вы хотите добавить это промежуточное ПО (быстрым способом) с возможностью выполнения промежуточного программного обеспечения после вас, вот как:
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Could not handle the request.");
// This ensures that any other middelware added after you runs.
await next();
});
Надеюсь, это поможет!
Ответ 3
Работает с различными кодами состояния, не указывая каждый отдельно в контроллере.
Startup.cs:
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseStatusCodePagesWithRedirects("/StatusCodes?statusCode={0}");
app.UseMvcWithDefaultRoute();
Контроллер:
public class StatusCodesController : Controller
{
public IActionResult Index(string statusCode)
{
if(statusCode == null) statusCode = "";
if(statusCode == "404") return View("Error404");
return View("Index",statusCode);
}
public IActionResult Test404() { return StatusCode(404); }
public IActionResult Test500() { return StatusCode(500); }
Вид:
@model string
@{ ViewData["Title"] = Model + " Oops!"; }
<style>
.error-template {
padding: 40px 15px;
text-align: center;
}
.error-actions {
margin-bottom: 15px;
margin-top: 15px;
}
.error-actions .btn {
margin-right: 10px;
}
</style>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="error-template">
<h2>Oops!</h2>
<h2>@Model Error</h2>
<div class="error-details">Sorry, an error has occurred!</div>
<div class="error-actions">
<a class="btn btn-primary btn-lg" href="/"><span class="glyphicon glyphicon-home"></span> Take Me Home </a>
<a class="btn btn-default btn-lg" href="/Home/ContactUs"><span class="glyphicon glyphicon-envelope"></span> Contact Support </a>
</div>
</div>
</div>
</div>
</div>