Подтвердить что ты не робот

ASP.NET Core эквивалент ASP.NET MVC 5 HttpException

В ASP.NET MVC 5 вы можете выдать HttpException с HTTP-кодом, и это установит ответ следующим образом:

throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request.");

HttpException не существует в ASP.NET Core. Какой эквивалентный код?

4b9b3361

Ответ 1

Я реализовал свое собственное HttpException и поддерживающее промежуточное ПО, которое перехватывает все HttpException и превращает их в соответствующий ответ об ошибке. Краткий отрывок можно увидеть ниже. Вы также можете использовать пакет Boxed.AspNetCore Nuget.

Пример использования в Startup.cs

public void Configure(IApplicationBuilder application)
{
    application.UseIISPlatformHandler();

    application.UseStatusCodePagesWithReExecute("/error/{0}");
    application.UseHttpException();

    application.UseMvc();
}

Метод расширения

public static class ApplicationBuilderExtensions
{
    public static IApplicationBuilder UseHttpException(this IApplicationBuilder application)
    {
        return application.UseMiddleware<HttpExceptionMiddleware>();
    }
}

Middleware

internal class HttpExceptionMiddleware
{
    private readonly RequestDelegate next;

    public HttpExceptionMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await this.next.Invoke(context);
        }
        catch (HttpException httpException)
        {
            context.Response.StatusCode = httpException.StatusCode;
            var responseFeature = context.Features.Get<IHttpResponseFeature>();
            responseFeature.ReasonPhrase = httpException.Message;
        }
    }
}

HttpException

public class HttpException : Exception
{
    private readonly int httpStatusCode;

    public HttpException(int httpStatusCode)
    {
        this.httpStatusCode = httpStatusCode;
    }

    public HttpException(HttpStatusCode httpStatusCode)
    {
        this.httpStatusCode = (int)httpStatusCode;
    }

    public HttpException(int httpStatusCode, string message) : base(message)
    {
        this.httpStatusCode = httpStatusCode;
    }

    public HttpException(HttpStatusCode httpStatusCode, string message) : base(message)
    {
        this.httpStatusCode = (int)httpStatusCode;
    }

    public HttpException(int httpStatusCode, string message, Exception inner) : base(message, inner)
    {
        this.httpStatusCode = httpStatusCode;
    }

    public HttpException(HttpStatusCode httpStatusCode, string message, Exception inner) : base(message, inner)
    {
        this.httpStatusCode = (int)httpStatusCode;
    }

    public int StatusCode { get { return this.httpStatusCode; } }
}

В долгосрочной перспективе я бы не советовал использовать исключения для возврата ошибок. Исключения медленнее, чем просто возвращать ошибку из метода.

Ответ 2

После короткого чата с @davidfowl кажется, что ASP.NET 5 не имеет такого понятия HttpException или HttpResponseException, которое "волшебным образом" превращается в ответные сообщения.

Что вы можете сделать, подключиться к конвейеру ASP.NET 5 через MiddleWare и создать тот, который обрабатывает исключения для вас.

Вот пример из исходного кода их промежуточного программного обеспечения обработчика ошибок, который установит код состояния ответа на 500 в случае исключения дальше по конвейеру:

public class ErrorHandlerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ErrorHandlerOptions _options;
    private readonly ILogger _logger;

    public ErrorHandlerMiddleware(RequestDelegate next, 
                                  ILoggerFactory loggerFactory,
                                  ErrorHandlerOptions options)
    {
        _next = next;
        _options = options;
        _logger = loggerFactory.CreateLogger<ErrorHandlerMiddleware>();
        if (_options.ErrorHandler == null)
        {
            _options.ErrorHandler = _next;
        }
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError("An unhandled exception has occurred: " + ex.Message, ex);

            if (context.Response.HasStarted)
            {
                _logger.LogWarning("The response has already started, 
                                    the error handler will not be executed.");
                throw;
            }

            PathString originalPath = context.Request.Path;
            if (_options.ErrorHandlingPath.HasValue)
            {
                context.Request.Path = _options.ErrorHandlingPath;
            }
            try
            {
                var errorHandlerFeature = new ErrorHandlerFeature()
                {
                    Error = ex,
                };
                context.SetFeature<IErrorHandlerFeature>(errorHandlerFeature);
                context.Response.StatusCode = 500;
                context.Response.Headers.Clear();

                await _options.ErrorHandler(context);
                return;
            }
            catch (Exception ex2)
            {
                _logger.LogError("An exception was thrown attempting
                                  to execute the error handler.", ex2);
            }
            finally
            {
                context.Request.Path = originalPath;
            }

            throw; // Re-throw the original if we couldn't handle it
        }
    }
}

И вам нужно зарегистрировать его с помощью StartUp.cs:

public class Startup
{
    public void Configure(IApplicationBuilder app, 
                          IHostingEnvironment env, 
                          ILoggerFactory loggerfactory)
    {
       app.UseMiddleWare<ExceptionHandlerMiddleware>();
    }
}

Ответ 3

В качестве альтернативы, если вы просто хотите вернуть произвольный код состояния и не связаны с подходом, основанным на исключении, вы можете использовать

return new HttpStatusCodeResult(400);

Обновление: с .NET Core RC 2 префикс Http отбрасывается. Теперь это:

return new StatusCodeResult(400);

Ответ 4

Базовый класс Microsoft.AspNet.Mvc.Controller предоставляет перегрузку HttpBadRequest(string), которая принимает сообщение об ошибке для возврата клиенту. Поэтому из-за действия контроллера вы можете вызвать:

return HttpBadRequest("Bad Request.");

В конечном счете мой нос говорит, что любые частные методы, вызванные из действия контроллера, должны либо полностью соответствовать http-контексту, либо возвращать IActionResult, либо выполнять какую-либо другую небольшую задачу, полностью изолированную от того факта, что она внутри конвейера http, Конечно, это мое личное мнение, но класс, который выполняет какую-то часть бизнес-логики, не должен возвращать коды статуса HTTP, а вместо этого должен бросать свои собственные исключения, которые можно поймать и перевести на уровне контроллера/действия.