Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 385 386 387 388 389 390 391 392 393 ... 407
class="p1">{

  public class CustomExceptionFilterAttribute : ExceptionFilterAttribute

  {

    public override void OnException(ExceptionContext context)

    {

    }

  }

}

В отличие от большинства фильтров в ASP.NET Core, которые имеют обработчик событий "перед" и "после", фильтры исключений располагают только одним обработчиком: OnException() (или OnExceptionAsync()). Обработчик принимает один параметр, ExceptionContext, который предоставляет доступ к ActionContext, а также к сгенерированному исключению.

Кроме того, фильтры принимают участие во внедрении зависимостей, позволяя получить доступ в коде к любому элементу внутри контейнера. В рассматриваемом примере вам необходим экземпляр реализации IWebHostEnvironment, внедренный в фильтр, который будет использоваться для выяснения среды времени выполнения. Если средой является Development, тогда ответ должен также включать трассировку стека. Добавьте переменную уровня класса для хранения экземпляра реализации IWebHostEnvironment и конструктор:

private readonly IWebHostEnvironment _hostEnvironment;

public CustomExceptionFilterAttribute(IWebHostEnvironment hostEnvironment)

{

  _hostEnvironment = hostEnvironment;

}

Код в обработчике OnException() проверяет тип сгенерированного исключения и строит соответствующий ответ. В случае среды Development в сообщение ответа включается трассировка стека. Затем создается динамический объект, который содержит значения для отправки вызывающему запросу, и возвращается в IActionResult. Вот модифицированный код метода:

public override void OnException(ExceptionContext context)

{

  var ex = context.Exception;

   string stackTrace = _hostEnvironment.IsDevelopment()

     ? context.Exception.StackTrace : string.Empty;

  string message = ex.Message;

  string error;

    IActionResult actionResult;

  switch (ex)

  {

    case DbUpdateConcurrencyException ce:

      // Возвращается код HTTP 400.

      error = "Concurrency Issue.";

      actionResult = new BadRequestObjectResult(

        new {Error = error, Message = message, StackTrace = stackTrace});

      break;

    default:

      error = "General Error.";

      actionResult = new ObjectResult(

        new {Error = error, Message = message, StackTrace = stackTrace})

      {

        StatusCode = 500

      };

      break;

  }

  //context.ExceptionHandled = true; // Если убрать здесь комментарий,

                                     // то исключение поглощается

  context.Result = actionResult;

}

Если вы хотите, чтобы фильтр исключений поглотил исключение и установил код состояния в 200 (скажем, для регистрации ошибки в журнале, не возвращая ее клиенту), тогда поместите следующую строку перед установкой Result (в предыдущем примере кода просто уберите комментарий):

context.ExceptionHandled = true;

Добавление фильтров в конвейер обработки

Фильтры можно применять к методам действий, контроллерам или глобально к приложению. Код "перед" фильтров выполняется снаружи вовнутрь (глобальный, контроллер, метод действия), в то время как код "после" фильтров выполняется изнутри наружу (метод действия, контроллер, глобальный).

На уровне приложения фильтры добавляются в методе ConfigureServices() класса Startup. Откройте файл класса Startup.cs и поместите в начало файла следующий оператор using:

using AutoLot.Api.Filters;

Модифицируйте метод AddControllers(), добавив специальный фильтр:

services

  .AddControllers(config => config.Filters.Add(

      new CustomExceptionFilterAttribute(_env)))

  .AddJsonOptions(options =>

  {

    options.JsonSerializerOptions.PropertyNamingPolicy = null;

    options.JsonSerializerOptions.WriteIndented = true;

  })

  .ConfigureApiBehaviorOptions(options =>

  {

  ...

  });

Тестирование фильтра исключений

Чтобы протестировать фильтр исключений, откройте файл WeatherForecastController.cs и обновите метод действия Get() показанным ниже кодом:

[HttpGet]

public IEnumerable<WeatherForecast> Get()

{

  _logger.LogAppWarning("This is a test");

  throw new Exception("Test Exception");

  ...

}

Запустите приложение и испытайте метод с использованием Swagger. Результаты, отображенные в пользовательском интерфейсе Swagger должны соответствовать следующему выводу (трассировка стека приведена с сокращениями):

{

  "Error": "General Error.",

  "Message": "Test Exception",

  "StackTrace": "   at AutoLot.Api.Controllers.WeatherForecastController.Get() in

D:\Projects\Books\csharp9-wf\Code\New\Chapter_30\AutoLot.Api\Controllers\

WeatherForecastController.cs:line 31rn  "

}

Добавление поддержки запросов между источниками

Приложения API должны иметь политики, которые разрешают или запрещают взаимодействовать с ними клиентам, обращающимся из другого сервера. Такие типы запросов называются запросами между источниками (cross-origin requests — CORS). Хотя в этом нет необходимости при работе локально на своей машине для всего мира ASP.NET Core, поддержка CORS нужна фреймворкам JavaScript, которые желают взаимодействовать с вашим приложением API, даже когда они все вместе функционируют локально.

На заметку! Дополнительные сведения о поддержке CORS ищите в документации по ссылке https://docs.microsoft.com/ru-ru/aspnet/core/security/cors.

Создание политики CORS

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

Конфигурирование начинается с создания политики CORS и добавления ее в коллекцию служб. Политика имеет имя (оно будет использоваться в методе Configure()), за которым следуют правила. Далее будет сознана политика по имени AllowAll, разрешающая все. Добавьте в метод ConfigureServices() класса Startup следующий код:

services.AddCors(options =>

{

  options.AddPolicy("AllowAll", builder =>

  {

   builder

      .AllowAnyHeader()

      .AllowAnyMethod()

      .AllowAnyOrigin();

  });

});

Добавление политики CORS в конвейер обработки HTTP

Наконец, политику CORS необходимо добавить в конвейер обработки HTTP. Поместите между вызовами арр. UseRouting() и арр.UseEndpoints() в методе Configure() класса Startup показанную ниже строку (выделенную полужирным):

public void Configure(

  IApplicationBuilder app,

  IWebHostEnvironment env,

  ApplicationDbContext context)

{

  ...

  // Включить маршрутизацию.

  app.UseRouting();

  // Добавить политику CORS.

  app.UseCors("AllowAll");

  // Включить проверки авторизации.

  app.UseAuthorization();

  ...

}

Резюме

В главе вы продолжили изучение ASP.NET Core. Сначала вы узнали о возвращении данных JSON из методов действий, после чего взглянули на атрибут ApiController и его влияние на контроллеры API. Затем вы обновили общую реализацию Swashbuckle, чтобы включить XML-документацию приложения и информацию из атрибутов методов действий.

Далее был построен базовый контроллер, содержащий большинство функциональности приложения. После этого в проект были добавлены производные контроллеры, специфичные для сущностей. В заключение был добавлен фильтр исключений уровня приложения

1 ... 385 386 387 388 389 390 391 392 393 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий