在 ASP.NET MVC 5 中,您可以使用 HTTP 代码引发HttpException,这将设置响应如下:
throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request.");
HttpException
在 ASP.NET Core 中不存在。什么是等效代码?
在 ASP.NET MVC 5 中,您可以使用 HTTP 代码引发HttpException,这将设置响应如下:
throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request.");
HttpException
在 ASP.NET Core 中不存在。什么是等效代码?
我实现了我自己的HttpException
和支持的中间件,它捕获所有HttpException
的并将它们转换为相应的错误响应。下面可以看到一个简短的摘录。您还可以使用Boxed.AspNetCore Nuget 包。
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; } }
}
从长远来看,我建议不要使用异常来返回错误。异常比仅从方法返回错误要慢。
在与@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>();
}
}
或者,如果您只想返回任意状态代码并且不关心基于异常的方法,您可以使用
return new HttpStatusCodeResult(400);
更新:从 .NET Core RC 2 开始,Http 前缀被删除。就是现在:
return new StatusCodeResult(400);
Microsoft.AspNet.Mvc.Controller
基类公开了一个重载,该HttpBadRequest(string)
重载将错误消息返回给客户端。因此,在控制器操作中,您可以调用:
return HttpBadRequest("Bad Request.");
最后,我的鼻子说,从控制器操作中调用的任何私有方法都应该完全支持 http-context-aware 并返回一个IActionResult
,或者执行一些完全独立于它在 http 管道内部的事实的其他小任务。当然这是我个人的观点,但是执行某些业务逻辑的类不应该返回 HTTP 状态代码,而应该抛出自己的异常,这些异常可以在控制器/操作级别被捕获和翻译。
ASP.NET Core 本身没有等价物。正如其他人所说,实现这一点的方法是使用中间件和您自己的异常。
Opw.HttpExceptions.AspNetCore NuGet 包正是这样做的。
用于通过 HTTP 返回异常的中间件和扩展,例如 ASP.NET Core 问题详细信息。问题详细信息是一种机器可读格式,用于指定基于https://www.rfc-editor.org/rfc/rfc7807的 HTTP API 响应中的错误。但您不仅限于将异常结果作为问题详细信息返回,还可以为自己的自定义格式创建自己的映射器。
它是可配置的并且有据可查。
以下是开箱即用提供的例外列表:
从 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
这是@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)
{
}
}
使用此代码,我得到了比使用更好的结果: