![](/img/trans.png)
[英]ASP.NET Core equivalent for ASP.NET MVC BeginExecuteCore
[英]ASP.NET Core equivalent of ASP.NET MVC 5's HttpException
在 ASP.NET MVC 5 中,您可以使用 HTTP 代码抛出HttpException ,这将设置响应如下:
throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request.");
ASP.NET Core 中不存在HttpException
。 什么是等效代码?
我实现了我自己的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 上下文并返回IActionResult
,或者执行一些其他小任务,与它位于 http 管道内的事实完全隔离。 当然,这是我个人的意见,但是执行某些业务逻辑的类不应该返回 HTTP 状态代码,而应该抛出自己的异常,这些异常可以在控制器/操作级别捕获和转换。
ASP.NET Core 本身没有等价物。 正如其他人所说,实现这一点的方法是使用中间件和您自己的例外。
Opw.HttpExceptions.AspNetCore NuGet 包正是这样做的。
用于通过 HTTP 返回异常的中间件和扩展,例如作为 ASP.NET Core 问题详细信息。 问题详细信息是一种机器可读格式,用于指定基于https://tools.ietf.org/html/rfc7807 的HTTP API 响应中的错误。 但您不仅限于将异常结果作为问题详细信息返回,还可以为自己的自定义格式创建自己的映射器。
它是可配置的并且有据可查。
以下是现成可用的异常列表:
4xx从 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 缓存。
如果你使用这个和 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)
{
}
}
我使用此代码获得了比使用更好的结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.