обработка исключения в базовом контроллере ASP .NET 3.1 при использовании страниц razor

У меня есть веб-сайт ASP .NET Core 3.1, который использует бритвенные страницы, но также имеет один контроллер, наследуемый от класса ASP .NET Core Controller. Контроллер обрабатывает полезную нагрузку, а затем в случае успеха перенаправляет на одну из бритвенных страниц. Я замечаю, что когда в контроллере есть необработанное исключение, браузер отображает ошибку HTTP 400 - недопустимый запрос, но я хочу, чтобы контроллер просто использовал обработчик исключений, который я уже определил, который выглядит следующим образом:

if (env.IsDevelopment())
   app.UseDeveloperExceptionPage();
else
   app.UseExceptionHandler("/Error");

В приведенном выше примере путь "/ Error" - это страница бритвы. В режиме без разработки контроллер не использует мой обработчик исключений и просто отображает ошибку браузера HTTP 400 - недопустимый запрос.

Мне удалось заставить его работать с классом фильтра исключений, где внутри метода OnException () я регистрирую ошибку и вручную перенаправляю на страницу «/ Error». Фильтр исключений выглядит так:

private class CustomExceptionFilter : IExceptionFilter
{
    private readonly IWebHostEnvironment hostingEnvironment;

    private readonly ILogger<CustomExceptionFilter> logger;

    public CustomExceptionFilter(IWebHostEnvironment hostingEnvironment, ILogger<CustomExceptionFilter> logger)
    {
        this.hostingEnvironment = hostingEnvironment;
        this.logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        if (this.hostingEnvironment.IsDevelopment())
        {
            return;
        }

        this.logger.LogError(context.Exception, string.Empty);
        context.Result = new RedirectToPageResult("/Error");
    }

Затем я определил [TypeFilter (typeof (CustomExceptionFilter))] на самом контроллере. Вроде все работает, но вроде много движущихся частей. Это единственный способ сделать это или, может быть, я что-то упускаю?

Вот код запуска:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseForwardedHeaders();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");

        app.UseHsts(options => options.MaxAge(365).IncludeSubdomains());
    }

    app.UseStaticFiles();

    app.UseCookiePolicy();

    app.UseXRobotsTag(options => options.NoIndex().NoFollow());

    app.UseXfo(options => options.SameOrigin());

    app.UseXXssProtection(options => options.EnabledWithBlockMode());

    app.UseXContentTypeOptions();

    app.UseNoCacheHttpHeaders();

    app.UseRedirectValidation();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
}

Заранее спасибо!


person Eric    schedule 26.04.2020    source источник
comment
Есть ли что-нибудь в ваших файлах web.config или Startup.cs (или аналогичных), что может мешать работе вашего кода?   -  person Anthony McGrath    schedule 26.04.2020
comment
Я не мог найти ничего необычного. Смотрите код запуска в моем посте.   -  person Eric    schedule 26.04.2020


Ответы (3)


Попробуйте это app.UseExceptionHandler ("/ Home / Error"); Причина работы, пожалуйста, проверьте свой HomeController, ниже должен быть метод действия по умолчанию [ResponseCache (Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error () {return View (new ErrorViewModel {RequestId = Activity.Current? .Id ?? HttpContext.TraceIdentifier}); }

Если его там нет, вы можете создать этот метод в любом из своих контроллеров и указать путь к этому контроллеру, например. app.UseExceptionHandler ("/ YourController / Ошибка");

person Paresh Damani    schedule 26.04.2020
comment
У меня уже есть страница с ошибкой бритвы и я уже использую app.UseExceptionHandler (/ Error) - person Eric; 26.04.2020

Если вы хотите использовать app.UseExceptionHandler("/Error");, ваша страница Razor может выглядеть примерно так.

Error.cshtml

@page "/Error"
@model Pages.Error

@{
  Layout = null;
}

<h1>An unexpected error occured. Status Code: @HttpContext.Response.StatusCode</h1>

Error.cshtml.cs

public class Error : PageModel
  {
    private readonly ILogger<Error> _logger;

    public Error(ILogger<Error> logger)
    {
      _logger = logger;
    }

    public void OnGet()
    {
      var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();
      if(exceptionHandlerFeature?.Error != null)
        _logger.LogError($"This is a message from logger: {exceptionHandlerFeature.Error.Message}");
    }
  }
person vecilije    schedule 26.04.2020
comment
У меня уже есть общедоступный метод async Task OnGetAsync () на моей странице ошибки, но перенаправление на страницу ошибки не происходит, когда на моем контроллере возникает необработанное исключение. - person Eric; 26.04.2020
comment
Вот она: общедоступная асинхронная задача OnGetAsync () {ждите this.HttpContext.SignOutAsync (); } Но на самом деле этот метод не запускался в необработанных исключениях. Это был OnPostAsync (), который был уволен. Кроме того, я наконец понял, почему я получаю ошибку HTTP 400. Смотрите мой ответ - это произошло из-за жетона защиты от подделки. - person Eric; 27.04.2020

Я наконец понял, что случилось. Мой контроллер обрабатывал метод POST. Когда возникают какие-либо необработанные исключения, код пытается запустить мой обработчик исключений. Из-за POST он будет публиковаться на моей странице обработчика исключений, но это не удастся из-за отсутствия токена проверки запроса AntiForgery, поэтому он выдает HTTP 400 - Bad Request, который я видел раньше на своих страницах, использующих jQuery с AJAX, если токен скучал. Итак, в основном, чтобы решить эту проблему, я собираюсь добавить атрибут [IgnoreAntiforgeryToken] в мой обработчик страницы ошибок бритвы.

person Eric    schedule 26.04.2020