C# ASP.NET核心相当于ASP.NET MVC 5';https异常

C# ASP.NET核心相当于ASP.NET MVC 5';https异常,c#,.net,asp.net-core,asp.net-core-mvc,httpexception,C#,.net,Asp.net Core,Asp.net Core Mvc,Httpexception,在ASP.NET MVC 5中,您可以抛出一个带有HTTP代码的,这将设置如下响应: throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request."); HttpException在ASP.NET核心中不存在。什么是等效代码?在a之后,ASP.NET 5似乎没有“神奇地”变成响应消息的HttpException或HttpResponseException的概念 您可以做的是,创建一个为您处理异常的程序 下面是他们的错

在ASP.NET MVC 5中,您可以抛出一个带有HTTP代码的,这将设置如下响应:

throw new HttpException((int)HttpStatusCode.BadRequest, "Bad Request.");
HttpException
在ASP.NET核心中不存在。什么是等效代码?

在a之后,ASP.NET 5似乎没有“神奇地”变成响应消息的
HttpException
HttpResponseException
的概念

您可以做的是,创建一个为您处理异常的程序

下面是他们的错误处理程序中间件的示例,该中间件将在管道上出现异常时将响应状态代码设置为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
        }
    }
}

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

return new HttpStatusCodeResult(400);
更新:从.NET Core RC 2开始,Http前缀被删除。现在是:

return new StatusCodeResult(400);

我实现了自己的
HttpException
和支持中间件,它捕获所有
HttpException
,并将它们转换为相应的错误响应。下面是简短的摘录。您还可以使用Nuget包

Startup.cs中的使用示例 扩展方法
从长远来看,我建议不要使用异常来返回错误。异常比仅从方法返回错误要慢。

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

return HttpBadRequest("Bad Request.");

最终,我的鼻子说,从控制器操作中调用的任何私有方法都应该是完全http上下文感知的,并返回一个
IActionResult
,或者执行一些与http管道内部的事实完全隔离的其他小任务。虽然这是我个人的观点,但执行某些业务逻辑的类不应该返回HTTP状态码,而应该抛出自己的异常,这些异常可以在控制器/操作级别捕获和转换。

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

NuGet包正是这样做的

用于通过HTTP返回异常的中间件和扩展,如ASP.NET核心问题详细信息。问题详细信息是一种机器可读的格式,用于根据指定HTTP API响应中的错误。但您不仅限于将异常结果作为问题详细信息返回,还可以为自己的自定义格式创建自己的映射器

它是可配置的,并且有很好的文档记录

以下是开箱即用的例外情况列表:

4xx
  • 400 BadRequestException
  • 400 InvalidModelException
  • 400 ValidationErrorException
  • 400无效文件例外
  • 401未经授权的例外情况
  • 403禁止例外
  • 404 NotFoundException
  • 404 NotFoundException
  • 409冲突例外
  • 409保护异常
  • 415不支持的MediaTypeException
5xx
  • 500 InternalServerErrorException
  • 500 DbErrorException
  • 500序列化错误异常
  • 503 ServiceUnavailableException

从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);
}
[HttpGet(“{id}”)]
[产品响应类型(StatusCodes.Status200OK)]
[产品响应类型(StatusCodes.Status404NotFound)]
公共操作结果GetByItemId(int id)
{
...
如果(结果==null)
{
返回NotFound();
}
返回Ok(结果);
}

更多详情请参见:

这里是@muhammad rehan saeed answer的扩展版本。 它有条件地记录异常并禁用http缓存。
如果使用此选项并使用developerCeptionPage,则应在此之前调用UsedeveloperCeptionPage

Startup.cs:

app.UseMiddleware();
HttpExceptionMiddleware.cs

/**
*错误处理:在业务逻辑中抛出HTTPException,使用正确的httpStatusCode+短错误消息生成正确的响应。
*如果异常是服务器错误(状态5XX),则会记录此异常。
*/
内部类HttpExceptionMiddleware
{
私有只读请求委托下一步;
公共HttpExceptionMiddleware(RequestDelegate下一步)
{
this.next=next;
}
公共异步任务调用(HttpContext上下文)
{
尝试
{
等待这个。下一步。调用(上下文);
}
catch(httpe异常)
{
var-response=context.response;
if(response.HasStarted)
{
投掷;
}
int statusCode=(int)e.statusCode;

如果(statusCode>=500&&statusCode@Rehan这是我们必须编写的。他们不打算将该功能引入MVC 6。每个连接都将通过中间件管道完成。@Rehanseed我同意,这是非常有用的功能,我也经常使用它。ASP.NET 5是开源的,我们可以自己应用该功能如果我们愿意,我将添加您的代码并默认启用它。谢谢您的帮助。@davidfoll哪种扩展方法?@YuvalItzchakov我使用空的ASP.NET 5 Web API并实现nice 500错误页面可能来自此诊断中间件。如何替换此中间件或在生产中关闭?框架是否在测试之前预先注册它
启动。配置被调用的
?是的,直接在操作中调用肯定是最好的方法。但有时,操作调用执行特定工作的私有方法(返回ActionResult以外的内容),有时您希望此方法可以抛出异常以生成响应(主要是错误,比如400个错误请求,403个禁止)。在这种情况下,例外是一个不错的选择
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; } }
}
return HttpBadRequest("Bad Request.");
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ITEMS_TYPE> GetByItemId(int id)
{
...
    if (result == null)
    {
        return NotFound();
    }

    return Ok(result);
}