Redirect to error page mvc

Сегодня обсудим, как на asp.net mvc можно настроить обработку ошибок 404, 500, ну и любых других. Рассмотрим на примере 404 и 500, как наиболее популярных и важных. Как вместо стандартного не очень красивого желтого окна ошибки показывать свои собственные красивые интересные страницы, и при этом как правильно отдавать код ошибки в браузер пользователя.

Сегодня обсудим, как на asp.net mvc можно настроить обработку ошибок 404, 500, ну и любых других. Рассмотрим на примере 404 и 500, как наиболее популярных и важных. Как вместо стандартного не очень красивого желтого окна ошибки показывать свои собственные красивые интересные страницы, и при этом как правильно отдавать код ошибки в браузер пользователя.

Казалось бы, задача довольно тривиальная и может быть решена написанием буквально пары строк кода. Действительно, так и есть, если вы используете любую популярную серверную технологию. Но только не ASP.NET. Если ваше приложение написано на ASP.NET MVC, и вы первый раз сталкиваетесь с проблемой обработки ошибок, очень легко запутаться и сделать неправильные настройки. Что впоследствии негативно отразится на продвижении сайта в поисковых системах, удобстве работы для пользователя, SEO-оптимизации.

Рассмотрим два подхода, как настроить страницы ошибок. Они в целом похожи, какой выбрать – решать вам.

Для начала вспомним, что означают наиболее популярные коды ошибок, которые отдает сервер.

Код ответа 200. Это значит что все ОК. Запрос клиента обработан успешно, и сервер отдал затребованные клиентом данные в полном объеме. Например, пользователь кликнул по гиперссылке, и в ответ на это в браузере отобразилась нужная ему информация.

Код ответа 404. Это означает, что запрошенный клиентом ресурс не найден на сервере. Например, указанная в адресе гиперссылки статья не найдена, или *.pdf файл был удален и теперь недоступен для скачивания.

Код ответа 500. Внутренняя ошибка на сайте. Что-то сломалось. Это может быть все что угодно, от неправильно написанного кода программистом, до отказа оборудования на сервере.

Допустим, мы только что создали новое веб-приложение типа MVC. На текущий момент, если никаких дополнительных действий для обработки ошибок не принимать, то стандартный сценарий обработки ошибок будет работать как нужно. В браузер пользователя будет отдаваться правильный код ошибки, пользователю будет показана стандартная страница с ошибкой и ее описанием.

Стандартная страница ошибки

Стандартная страница ошибки

Теперь займемся настройкой собственных страниц ошибок. При этом для нас важно не только показать пользователю красивую страницу ошибки, но также сохранить правильный код ответа сервера.

Вариант 1. Ссылка на статичные заранее подготовленные html-страницы.

Первым делом в файле web.config в разделе system.web добавляем новую секцию customErrors со следующими настройками:

web.config

<system.web>
  <customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/404.aspx">
    <error statusCode="404" redirect="~/404.aspx"/>
    <error statusCode="500" redirect="~/500.aspx"/>
  </customErrors>
  ...
</system.web>

Эта секция служит для обработки ошибок на уровне платформы ASP.NET.

Атрибут mode=»On» определяет, что пользовательские страницы ошибок включены. Также допустимы значения Off / RemoteOnly.

Атрибут redirectMode=»ResponseRewrite» определяет, следует ли изменять URL-адрес запроса при перенаправлении на пользовательскую страницу ошибки. Естественно, нам этого не нужно.

Атрибут defaultRedirect=»~/404.aspx» указывает на то, какая страница ошибки будет показана в случае возникновения кода ответа сервера, который мы не описали в настройках. Пусть при любых других ошибках пользователь будет думать, что страница не найдена.

И уже внутри этой секции мы определяем два кода, для которых у нас будут кастомные страницы ошибок.

Далее, как видно из настроек выше, нам понадобятся *.aspx файлы, на которые будет делаться редирект. Обратите внимание, что мы ссылаемся именно на *.aspx файлы, а не на *.html. Эти файлы являются проходными, служебными, в них содержатся настройки для ответа сервера. Содержимое файла 404.aspx:

404.aspx

<%@ Page Language="C#" %>

<%
    var filePath = MapPath("~/404.html");
    Response.StatusCode = 404;
    Response.ContentType = "text/html; charset=utf-8";
    Response.WriteFile(filePath);
%>

В коде выше мы указываем путь непосредственно до конечного *.html файла, а также дополняем настройки ответа сервера. Указываем код ответа, тип отдаваемого контента и кодировку. Если не указать кодировку, то браузер пользователя может интерпретировать ответ от сервера как не отформатированную строку, и, соответственно, не преобразует ее в html-разметку. А если не указать StatusCode = 404 , то получится следующая интересная ситуация:

Код ответа сервера отдается неверно

Код ответа сервера отдается неверно

И хотя на рисунке выше нам показывается пользовательская страница с ошибкой, при этом код ответа 200 — это конечно же неверно. Когда-то давно на форумах Microsoft такое поведение зарепортили как баг. Однако Microsoft возразила, что это не баг, а фича и не стала ничего менять в будущих релизах ASP.NET. Поэтому приходится это исправлять вручную, и вручную в *.aspx файле в ответе сервера указывать код ответа 404.

Попробуйте собственноручно намеренно убрать какую-нибудь из объявленных на данный момент настроек из секции customErrors и понаблюдайте за результатом.

Также по аналогии создаем подобный *.aspx файл для ошибки 500.

И уже после этого нам нужно создать статичные html-файлы, соответственно для ошибок 404 и 500. Пусть они лежат в корне нашего проекта.

Статичные файлы расположены в корне проекта

Статичные файлы расположены в корне проекта

Здесь же в файле web.config определяем раздел system.WebServer, если он еще не определен, и в нем объявляем секцию httpErrors:

web.config

  <system.webServer>
    <httpErrors errorMode="Custom" defaultResponseMode="File" defaultPath="c:projectsmysite404.html">
      <remove statusCode="404" />
      <remove statusCode="500" />
      <error statusCode="404" path="404.html" responseMode="File" />
      <error statusCode="500" path="500.html" responseMode="File" />
    </httpErrors>
  </system.webServer>

Эта секция служит для обработки ошибок на уровне сервера IIS. Суть в том, что иногда обработка запроса происходит непосредственно на уровне ASP.NET. А иногда ASP.NET просто определяет нужный код ответа и пропускает запрос выше, на уровень сервера. Такой сценарий может случиться, если, например, мы в действии контроллера возвращаем экземпляр класса HttpNotFound:

Или же когда система маршрутизации в MVC-приложении не может определить, к какому маршруту отнести запрошенный пользователем URL-адрес:

https://site.com/long/long/long/long/path

Для секции httpErrors важно отметить следующее. Так как мы ссылаемся на статичные *.html файлы, то и в качестве значений для нужных атрибутов здесь также указываем File . Для атрибута defaultPath необходимо указать абсолютный путь до файла ошибки. Относительный путь именно в этом месте работать не будет. Сам атрибут defaultPath определяет файл, который будет выбран для всех других ошибок, которые мы явно не указали. Но здесь есть одна небольшая проблема. Дело в том, что этот атрибут по умолчанию заблокирован на сервере IIS Express. Если вы разрабатываете свое приложение именно на локальном сервере, то это ограничение нужно снять. Для этого в директории своего проекта нужно найти файл конфигурации сервера и удалить этот атрибут из заблокированных, как это показано на рисунке:

Расположение файла applicationhost.config

Расположение файла applicationhost.config

Также проверьте папку App_Start. Если вы создали не пустое приложение, а работаете над реальным проектом, там может находиться класс FilterConfig, в котором регистрируются все глобальные фильтры в приложении. В методе регистрации удалите строчку кода, где регистрируется HandleErrorAttribute, в нашем случае он не понадобится.

Вот такой комплекс мер нужно предпринять, чтобы настроить обработку ошибок 404, 500, и любых других. Это настройки в файле web.config, и добавление в наш проект статичных файлов.

Вариант 2. Обработка ошибок с использованием специального контроллера.

Второй подход немного отличается от первого. Здесь нам не понадобится секция customErrors, так как обработку всех ошибок мы будем передавать сразу из приложения на уровень сервера, и он уже будет решать что делать. Можно удалить или закомментировать эту секцию в файле web.config.

Далее создадим специальный контроллер, который будет принимать все ошибки, которые мы хотим обрабатывать:

public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View();
    }

    public ActionResult Internal()
    {
        Response.StatusCode = 500;
        return View();
    }
}

Также создадим соответствующие представления с нужной нам красивой разметкой.

Также в файле web.config нам нужно изменить настройки в секции httpErrors. Если раньше мы ссылались на статичные html-файлы, то теперь мы будем обращаться по указанным URL, которые мы определили в ErrorController’е, чтобы именно там обрабатывать ошибки:

web.config

<httpErrors errorMode="Custom" existingResponse="Replace" defaultResponseMode="ExecuteURL" defaultPath="/Error/NotFound">
  <remove statusCode="404"/>
  <remove statusCode="500"/>
  <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL"/>
  <error statusCode="500" path="/Error/Internal" responseMode="ExecuteURL"/>
</httpErrors>

Вариант 3. Фильтр HandleErrorAttribute

Замечу, что есть еще один способ взять под свой контроль обработку ошибок в приложении – это наследоваться от стандартного класса HandleErrorAttribute и написать свой фильтр. Но это уже более частный случай, когда нужно реализовать какую-то особенную логику при возникновении той или иной ошибки. В большинстве же более менее стандартных приложений наша проблема решается двумя выше описанными способами и в этом фильтре нет необходимости. Более подробную информацию, как работать с классом HandleErrorAttribute можно найти в официальной документации в интернете по этой ссылке.

Итого

Мы посмотрели на два разных подхода, которые можно применить при обработке ошибок на платформе ASP.NET. Опять же повторюсь, что если для вас не принципиально настраивать собственные страницы ошибок, то лучше не изменять эти настройки, так как даже одна упущенная деталь или неверно сконфигурированный параметр может очень сильно навредить репутации вашего сайта для конечного пользователя и в поисковых системах.

Настройка страниц ошибок

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 22.07.2016

С помощью двух секций customErrors и httpErrors в файле конфигурации мы можем задать в ASP.NET MVC 5 обработку статусных кодов ошибок.

Секция customErrors в web.config позволяет задать собственные страницы ошибок для различных статусных кодов HTTP. Правда, применение этой секции имеет ограничения.

Вначале добавим в проект свои страницы ошибок. Например, для обработки ошибки 404 добавим в корень проекта файл 404.html:

<!DOCTYPE html>
<html>
<head>
    <title>Ошибка 404</title>
	<meta charset="utf-8" />
</head>
<body>
    <h2>Ошибка 404. Ресурс не найден</h2>
</body>
</html>

Подобным образом добавим файлы и для других ошибок.

Далее найдем в файле конфигурации web.config секцию system.web и поместим в нее подсекцию
customErrors (если эта подсекция уже есть, изменим ее):

<system.web>
   <compilation debug="true" targetFramework="4.6" />
   <httpRuntime targetFramework="4.6" />
   
   <customErrors mode="On">
      <error statusCode="404" redirect="~/404.html"/>
      <error statusCode="403" redirect="~/403.html"/>
   </customErrors>
</system.web>

Внутри секции customErrors помещаются элементы error, каждый из которых задает код ошибки (атрибут statusCode)
и страницу переадресации при ошибке (атрибут redirect)

Если мы сейчас запустим приложение и обратимся к несуществующему ресурсу, то нам отобразится наша страница с ошибкой:

customErrors в ASP.NET MVC 5

Однако при такой переадресации мы сталкиваемся с рядом проблем. Во-первых, в качестве адреса используется не оригинальный путь, к которому идет
обращение, а 404.html. То есть вместо строки запроса /Home/Some, мы получаем /404.html?aspxerrorpath=/Home/Some.
Во-вторых, при отдаче ответа клиент получает статусный код 200, то есть запрос успешно обработан, вместо кода 404.

Чтобы решить первую проблему, добавим к определению секции атрибут redirectMode="ResponseRewrite":

<customErrors mode="On" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="~/404.html"/>
    <error statusCode="403" redirect="~/403.html"/>
</customErrors>

Теперь страницу с ошибкой можно будет увидеть напрямую по запрошенному пути. Однако клиенту все равно будут отдаваться статусный код 200.

Более того у нас есть еще и другая проблема. Если мы напрямую возвратим из метода контроллера статусный код ошибки, то этот код никак не будет обрабатываться, и настройки в
customErrors на него не подействуют. Например:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return HttpNotFound();
    }
}

При обращении к нему мы получим стандартное сообщение об ошибке:

NotFound in ASP.NET MVC 5

И для решения возникших проблем нам надо использовать не customErrors, а элемент httpErrors.

Вначале для обработки ошибок добавим в приложение новый контроллер ErrorController:

public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View();
    }

    public ActionResult Forbidden()
    {
        Response.StatusCode = 403;
        return View();
    }
}

Добавим представление для метода NotFound:

@{
    ViewBag.Title = "Ошибка 404";
}

<h2>Ошибка 404. Ресурс не найден</h2>

Подобным образом добавим представление и для других методов.

Далее добавим элемент httpErrors. Этот элемент помещается внутрь секции system.webServer. Если
этой секции внутри web.config нет, то ее можно добавить. А узел customErrors мы можем удалить или закомментировать:

<system.web>
   <compilation debug="true" targetFramework="4.6" />
   <httpRuntime targetFramework="4.6" />
    
   <!--<customErrors mode="On"  redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="~/Error/NotFound"/>
    <error statusCode="403" redirect="~/Error/Forbidden"/>
  </customErrors>-->
</system.web>
  
<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <clear/>
    <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL"/>
    <error statusCode="403" path="/Error/Forbidden" responseMode="ExecuteURL"/>
  </httpErrors>
</system.webServer>

Элемент httpErrors имеет ряд настроек. Чтобы протестировать настройки локально, устанавливается атрибут errorMode="Custom".
Если тестирование необязательно, и приложение уже развернуто для использования, то можно установить значение errorMode="DetailedLocalOnly".

Значение existingResponse="Replace" позволит отобразить ошибку по оригинальному запрошенному пути без переадресации.

Внутри элемента httpErrors с помощью отдельных элементов error устанавливается обработка ошибок. Атрибут statusCode
задает статусный код, атрибут path — адрес url, который будет вызываться, а атрибут responseMode указывает, как будет обрабатываться ответ вызванному url.
Атрибут responseMode может принимать три значения:

  • ExecuteURL: производит рендеринг ответа полученного при вызове адреса url из атрибута path

  • Redirect: выполняет переадресацию со статусным кодом 302

  • File: рассматривает адрес url из атрибута path как статическую страницу и использует ее в качестве ответа

Настройки элемента httpErrors могут наследоваться с других уровней, например, от файла конфигурации machine.config. И чтобы удалить
все унаследованные настройки, применяется элемент <clear />. Чтобы удалить настройки для отдельных ошибок, применяется элемент
<remove />:

<httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404"/>
    <remove statusCode="403"/>
    <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL"/>
    <error statusCode="403" path="/Error/Forbidden" responseMode="ExecuteURL"/>
</httpErrors>

И теперь, если мы запустим приложение и обратимся по несуществующему пути или к методу, который возвращает статусный код 404, то у нас отобразится ответ от метода NotFound контроллера
ErrorController:

Настройка страниц ошибок в ASP.NET MVC 5

Установка атрибута responseMode="File" позволяет использовать в качестве ответа статические файлы. Например, используем ранее определенные файлы ошибок:

<httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404"/>
    <remove statusCode="403"/>
    <error statusCode="404" path="404.html" responseMode="File"/>
    <error statusCode="403" path="403.html" responseMode="File"/>
</httpErrors>

Posts | About

April 16, 2019 by Areg Sarkissian

Introduction

It is critical to have global exception handling for ASP.NET Core applications to respond appropriately to exceptions that are not handled by application logic.

Global exception handling allows us to log all unhandled exceptions in a central location in our application and then provide a user friendly response to the user.

In ASP.NET MVC projects, there are generally two types of content returned to the web browser. There are normal web page requests that require returning HTML content and there are AJAX requests that normally require returning JSON formatted content.

When the browser requests a HTML rendered page and an exception occurs that the application cannot handle, we generally redirect the browser to an HTML error page.

However, when the browser makes an AJAX request that expects a JSON response then we need to return a JSON error response instead of redirecting to a HTML error page.

Given this, in a global exception handler, we need to distinguish between normal web page requests, so that we can return the appropriate error response.

Using HTTP request headers in the Global Exception Handler

The way we can detect if an AJAX request expects a JSON response is by inspecting the HTTP Accept header sent by the request.

The global exception handler in our MVC application can determine whether to send a JSON error response or redirect to a HTML error page based on the value of the Accept header.

If an Accept header exists that contains the value application/json, then the handler needs to respond with a JSON error response.

Note: Detecting if a request is an AJAX request is not the same as detecting whether the request accepts a JSON response. To detect an AJAX request you can check for a X-Requested-With request header that contains the value xmlhttprequest.

Adding a Global exception handler middleware

We can add a Global exception handler middleware that can access the unhandled exception and the request headers from the HTTP request context to decide how to format the exception data for the response.

This middleware will return JSON data for requests that contain the applicationjson Accept header and otherwise will redirect to an HTML error page.

Also the middleware will serialize and log the exception information.

Below you can see my sample implementation of the global exception handler middleware implemented as an IApplicationBuilder extension method:

public static class GlobalExceptionHandlerExtension
{
    //This method will globally handle logging unhandled execeptions.
    //It will respond json response for ajax calls that send the json accept header
    //otherwise it will redirect to an error page
    public static void UseGlobalExceptionHandler(this IApplicationBuilder app
                                                , ILogger logger
                                                , string errorPagePath
                                                , bool respondWithJsonErrorDetails=false)
    {
        app.UseExceptionHandler(appBuilder =>
        {
            appBuilder.Run(async context =>
            {
                //============================================================
                //Log Exception
                //============================================================
                var exception = context.Features.Get<IExceptionHandlerFeature>().Error;

                string errorDetails = $@"{exception.Message}
                                         {Environment.NewLine}
                                         {exception.StackTrace}";

                int statusCode = (int)HttpStatusCode.InternalServerError;

                context.Response.StatusCode = statusCode;

                var problemDetails = new ProblemDetails
                {
                    Title = "Unexpected Error",
                    Status = statusCode,
                    Detail = errorDetails,
                    Instance = Guid.NewGuid().ToString()
                };

                var json = JsonConvert.SerializeObject(problemDetails);

                logger.LogError(json);

                //============================================================
                //Return response
                //============================================================
                var matchText="JSON";

                bool requiresJsonResponse = context.Request
                                                    .GetTypedHeaders()
                                                    .Accept
                                                    .Any(t => t.Suffix.Value?.ToUpper() == matchText
                                                              || t.SubTypeWithoutSuffix.Value?.ToUpper() == matchText);

                if (requiresJsonResponse)
                {
                    context.Response.ContentType = "application/json; charset=utf-8";

                    if(!respondWithJsonErrorDetails)
                        json = JsonConvert.SerializeObject(new { Title = "Unexpected Error"
                                                               , Status = statusCode});
                    await context.Response
                                    .WriteAsync(json, Encoding.UTF8);
                }
                else
                {
                    context.Response.Redirect(errorPagePath);

                    await Task.CompletedTask;
                }
            });
        });
    }
}

ASP.NET Core 2.2 has infrastructure code that makes it easy to parse out the Accept header components and an error data container that can be serialized to JSON and returned as a response.

The handler first logs the error using the supplied logger and then returns the proper response based on the content of the Accept header.

An additional flag is used to limit the JSON data returned in the response.

We can now replace the original app.UseExceptionHandler("/Home/Error") call in the Startup.Configure(...) method with our own exception handler middleware:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseGlobalExceptionHandler( _logger
                                    , errorPagePath: "/Home/Error"
                                    , respondWithJsonErrorDetails: true);

        //Replaced UseExceptionHandler with UseGlobalExceptionHandler
        //app.UseExceptionHandler("/Home/Error");

        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

The complete source code of the demo app can be found in my Github https://github.com/aregsar/mvcapp.

Testing the Global Exception Handler middleware

To do a quick test of the installed the global exception handler middleware, I added an Ajax action method to the HomeController class. The method normally returns JSON data but throws an exception if the route contains the optional id parameter.

I also modified the Privacy action method that normally returns the Privacy view but throws an exception if the route contains the id parameter.

Here is the code for these action methods:

public IActionResult Privacy(int? id)
{
    if(id.HasValue)
        throw new Exception("privacy page exception");

    return View();
}

public IActionResult Ajax(int? id)
{
    if(id.HasValue)
        throw new Exception("ajax exception");

    return Json(new {name="ajax"});
}

Now, looking in the Startup.Configure(...) method we can see that the global exception handler middleware is installed in the middleware pipeline only for production builds.

Therefore, to run the server in production mode, I added a Production run configuration profile in the profiles section of the propertieslaunchSettings.json file.

Here is the production configuration from the launchSettings file:

 "prod": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Production"
      }

After adding the configuration profile we can use the dotnet run command with the –launch-profile option to run the app in production mode.

dotnet run --launch-profile prod

We can now quickly test the global exception handling middleware code by issuing curl commands against the Ajax action endpoint.

To do so we can open a new terminal tab and curl a request to the https://localhost:5001/home/ajax URL:

curl -i -H "Accept: application/json" https://localhost:5001/home/ajax
HTTP/1.1 200 OK
Date: Thu, 11 Apr 2019 22:47:56 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

{"name":"ajax"}

We can see the normal JSON response of the Ajax action method since there was no unhandled exception.

Next we can add an id parameter to the URL to activate the exception in the Ajax action method:

curl -i -H "Accept: application/json" https://localhost:5001/home/ajax/1
HTTP/1.1 500 Internal Server Error
Date: Thu, 11 Apr 2019 22:46:27 GMT
Content-Type: application/json
Server: Kestrel
Cache-Control: no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Expires: -1

{
  "title": "Unexpected error",
  "status": 500,
  "detail": "test exceptionrn                                             nrn                                                at mvcapp.Controllers.HomeController.ajax(Nullable`1 id) in /Users/aregsarkissian/projects/asp3/mvcapp/Controllers/HomeController.cs:line 29n   at lambda_method(Closure , Object , Object[] )n   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)n   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)n   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()n   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()n   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)n   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)n   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()n   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()n   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)n   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)n   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()n   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()n   at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)n   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)n   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)n   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)",
  "instance": "9f238f4e-97b4-478d-9ee3-96e91cb1a93c"
}

This time we can see that the response includes the JSON formatted exception data returned by the global exception handler.

Also if we look at the terminal tab where we ran the application, we can see that the unhandled exception is logged as JSON data to the console by the global exception handler.

Next we can quickly test the global exception handler when sending requests to the Privacy action method, by using the web browser to navigate to the Privacy endpoint URL:

https://localhost:5001/home/privacy

We can see the normal privacy HTML page response displayed in the browser.

Finally we can add the id parameter to the Privacy endpoint URL and navigate to the URL to activate the exception in the Privacy action method:

https://localhost:5001/home/privacy/1

This time we can see that we are redirected to a server error page as usual for HTML endpoints that throw unhandled exceptions.

Conclusion

It is easy to add a global exception handling middleware to ASP.NET Core MVC applications to perform custom exception handling.

ASP.NET Core gives us all the facilities that we need to access information in the request headers and the exception data to make our own decision on how we want to respond to unhandled application errors.

Thanks for reading

Понравилась статья? Поделить с друзьями:
  • Redirect standard error standard output
  • Redirect error output cmd
  • Redirect error output bash
  • Redirect console error c1
  • Redefinition of function error