77

在 ASP.NET MVC 5 中,您可以使用 HTTP 代码引发HttpException,这将设置响应如下:

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

HttpException在 ASP.NET Core 中不存在。什么是等效代码?

4

7 回答 7

54

我实现了我自己的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>();
    }
}

中间件

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;
        }
    }
}

异常

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; } }
}

从长远来看,我建议不要使用异常来返回错误。异常比仅从方法返回错误要慢。

于 2016-03-06T16:51:15.303 回答
26

与@davidfowl 简短交谈之后,似乎 ASP.NET 5 没有这样的概念,HttpException或者HttpResponseException“神奇地”转向响应消息。

您可以做的是通过 MiddleWare 连接到 ASP.NET 5 管道,并创建一个为您处理异常的管道。

这是他们的错误处理程序中间件源代码中的一个示例,它将在管道进一步出现异常的情况下将响应状态代码设置为 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>();
    }
}
于 2015-06-25T15:30:14.323 回答
13

或者,如果您只想返回任意状态代码并且不关心基于异常的方法,您可以使用

return new HttpStatusCodeResult(400);

更新:从 .NET Core RC 2 开始,Http 前缀被删除。就是现在:

return new StatusCodeResult(400);
于 2015-10-09T18:18:34.013 回答
6

Microsoft.AspNet.Mvc.Controller基类公开了一个重载,该HttpBadRequest(string)重载将错误消息返回给客户端。因此,在控制器操作中,您可以调用:

return HttpBadRequest("Bad Request.");

最后,我的鼻子说,从控制器操作中调用的任何私有方法都应该完全支持 http-context-aware 并返回一个IActionResult,或者执行一些完全独立于它在 http 管道内部的事实的其他小任务。当然这是我个人的观点,但是执行某些业务逻辑的类不应该返回 HTTP 状态代码,而应该抛出自己的异常,这些异常可以在控制器/操作级别被捕获和翻译。

于 2016-04-25T06:33:05.323 回答
6

ASP.NET Core 本身没有等价物。正如其他人所说,实现这一点的方法是使用中间件和您自己的异常。

Opw.HttpExceptions.AspNetCore NuGet 包正是这样做的。

用于通过 HTTP 返回异常的中间件和扩展,例如 ASP.NET Core 问题详细信息。问题详细信息是一种机器可读格式,用于指定基于https://www.rfc-editor.org/rfc/rfc7807的 HTTP API 响应中的错误。但您不仅限于将异常结果作为问题详细信息返回,还可以为自己的自定义格式创建自己的映射器。

它是可配置的并且有据可查。

以下是开箱即用提供的例外列表:

4xx

  • 400 错误请求异常
  • 400 无效模型异常
  • 400 验证错误异常<T>
  • 400 无效文件异常
  • 401 未授权异常
  • 403 禁止异常
  • 404 未找到异常
  • 404 未找到异常<T>
  • 409 冲突异常
  • 409 受保护的异常
  • 415 不支持的媒体类型异常

5xx

  • 500 内部服务器错误异常
  • 500 数据库错误异常
  • 500 序列化错误异常
  • 503 服务不可用异常
于 2020-03-06T12:26:12.600 回答
2

从 ASP.NET Core 3 开始,您可以使用它ActionResult来返回 HTTP 状态代码:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ITEMS_TYPE> GetByItemId(int id)
{
...
    if (result == null)
    {
        return NotFound();
    }

    return Ok(result);
}

更多详细信息在这里:https ://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-3.1

于 2020-03-26T15:09:22.600 回答
2

这是@muhammad-rehan-saeed 答案的扩展版本。它有条件地记录异常并禁用 http 缓存。
如果使用 this 和 UseDeveloperExceptionPage,则应在此之前调用 UseDeveloperExceptionPage 。

启动.cs:

app.UseMiddleware<HttpExceptionMiddleware>();

HttpExceptionMiddleware.cs

/**
 * Error handling: throw HTTPException(s) in business logic, generate correct response with correct httpStatusCode + short error messages.
 * If the exception is a server error (status 5XX), this exception is logged.
 */
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 e)
        {
            var response = context.Response;
            if (response.HasStarted)
            {
                throw;
            }

            int statusCode = (int) e.StatusCode;
            if (statusCode >= 500 && statusCode <= 599)
            {
                logger.LogError(e, "Server exception");
            }
            response.Clear();
            response.StatusCode = statusCode;
            response.ContentType = "application/json; charset=utf-8";
            response.Headers[HeaderNames.CacheControl] = "no-cache";
            response.Headers[HeaderNames.Pragma] = "no-cache";
            response.Headers[HeaderNames.Expires] = "-1";
            response.Headers.Remove(HeaderNames.ETag);

            var bodyObj = new {
                Message = e.BaseMessage,
                Status = e.StatusCode.ToString()
            };
            var body = JsonSerializer.Serialize(bodyObj);
            await context.Response.WriteAsync(body);
        }
    }
}

HTTPException.cs

public class HttpException : Exception
{
    public HttpStatusCode StatusCode { get; }

    public HttpException(HttpStatusCode statusCode)
    {
        this.StatusCode = statusCode;
    }

    public HttpException(int httpStatusCode)
        : this((HttpStatusCode) httpStatusCode)
    {
    }

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

    public HttpException(int httpStatusCode, string message)
        : this((HttpStatusCode) httpStatusCode, message)
    {
    }

    public HttpException(HttpStatusCode statusCode, string message, Exception inner)
        : base(message, inner)
    {
    }

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

使用此代码,我得到了比使用更好的结果:

  • 使用异常处理程序:
    • 自动记录每个“正常”异常(例如 404)。
    • 在开发模式下禁用(调用 app.UseDeveloperExceptionPage 时)
    • 不能只捕获特定的异常
  • Opw.HttpExceptions.AspNetCore:当一切正常时记录异常

另请参阅ASP.NET Core Web API 异常处理

于 2021-02-26T09:56:12.340 回答