如何从ASP.NET Core RC2 Web Api返回HTTP 500?


187

回到RC1,我会这样做:

[HttpPost]
public IActionResult Post([FromBody]string something)
{    
    try{
        // ...
    }
    catch(Exception e)
    {
         return new HttpStatusCodeResult((int)HttpStatusCode.InternalServerError);
    }
}

在RC2中,不再有HttpStatusCodeResult,并且没有什么可以让我返回500类型的IActionResult。

现在,针对我的要求,该方法是否完全不同?我们不再尝试捕获Controller代码了吗?我们是否只是让框架向API调用者抛出泛型500异常?对于开发,如何查看确切的异常堆栈?

Answers:


238

从我可以看到,ControllerBase类中有一些辅助方法。只需使用StatusCode方法:

[HttpPost]
public IActionResult Post([FromBody] string something)
{    
    //...
    try
    {
        DoSomething();
    }
    catch(Exception e)
    {
         LogException(e);
         return StatusCode(500);
    }
}

您还可以使用StatusCode(int statusCode, object value)也会协商内容的重载。


7
这样做会丢失CORS标头,因此浏览器客户端会隐藏错误。V令人沮丧。
bbsimonbb

2
@bbsimonbb内部错误应该对客户端隐藏。他们应该记录为开发人员。
喜马拉雅山Garg

10
传统上,开发人员应该享有选择返回错误信息级别的特权。
bbsimonbb

177

如果您不希望对特定数字进行硬编码,则可以使用Microsoft.AspNetCore.Mvc.ControllerBase.StatusCodeMicrosoft.AspNetCore.Http.StatusCodes来形成响应。

return  StatusCode(StatusCodes.Status500InternalServerError);

更新:2019年8月

也许与原始问题没有直接关系,但是当我尝试获得相同的结果时,Microsoft Azure Functions我发现必须构造一个StatusCodeResultMicrosoft.AspNetCore.Mvc.Core程序集中找到的新对象。我的代码现在看起来像这样;

return new StatusCodeResult(StatusCodes.Status500InternalServerError);

11
太好了,避免了任何硬编码的部分/“魔术数字”。我以前使用过StatusCode((int)HttpStatusCode.InternalServerError),但我更喜欢您。
aleor

1
当时我没有考虑的一件事是它使代码更具可读性,回到它之后,您就知道错误号500与什么相关,它就在代码中。自我记录:-)
爱德华·科莫

11
我无法想象内部服务器错误(500)很快就会改变。

2
太棒了 这也确实清理了我的招摇属性。例如:[ProducesResponseType(StatusCodes.Status500InternalServerError)]
redwards510

43

如果您需要回应,请致电

return StatusCode(StatusCodes.Status500InternalServerError, responseObject);

这将返回500与响应对象...


3
如果您不想创建特定的响应对象类型:return StatusCode(StatusCodes.Status500InternalServerError, new { message = "error occurred" });当然,您可以根据需要添加描述性消息以及其他元素。
Mike Taverne

18

一个更好的办法来处理这个截至目前(1.1)是为此在Startup.csConfigure()

app.UseExceptionHandler("/Error");

这将执行以下路线 /Error。这样可以避免将try-catch块添加到您编写的每个操作中。

当然,您需要添加类似于以下内容的ErrorController:

[Route("[controller]")]
public class ErrorController : Controller
{
    [Route("")]
    [AllowAnonymous]
    public IActionResult Get()
    {
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

更多信息在这里


如果您想获取实际的异常数据,可以将其添加到上面 Get()return语句之前的右上方。

// Get the details of the exception that occurred
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();

if (exceptionFeature != null)
{
    // Get which route the exception occurred at
    string routeWhereExceptionOccurred = exceptionFeature.Path;

    // Get the exception that occurred
    Exception exceptionThatOccurred = exceptionFeature.Error;

    // TODO: Do something with the exception
    // Log it with Serilog?
    // Send an e-mail, text, fax, or carrier pidgeon?  Maybe all of the above?
    // Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
}

以上摘录自Scott Sauber的博客


这太棒了,但是我该如何记录抛出的异常?
redwards510

@ redwards510这是您的操作方式:scottsauber.com/2017/04/03/…由于这是一个非常常见的用例,我将更新我的答案以反映它
gldraphael

@gldraphael我们目前正在使用Core 2.1。Scott的博客很棒,但是我很好奇当前是否建议使用IExceptionHandlerPathFeature作为最佳实践。也许创建自定义中间件更好?
帕维尔

@Pavel我们在ExceptionHandler这里使用中间件。当然,您可以自己滚动或按自己的意愿扩展它。这是到资源链接。编辑:看到这一行IExceptionHandlerPathFeature
gldraphael

15
return StatusCode((int)HttpStatusCode.InternalServerError, e);

应该在非ASP.NET上下文中使用(请参阅ASP.NET Core的其他答案)。

HttpStatusCode是中的枚举System.Net


11

如何创建一个表示内部服务器错误的自定义ObjectResult类,例如OkObjectResult?您可以在自己的基类中放置一个简单的方法,以便可以轻松生成InternalServerError,并像Ok()或一样返回它BadRequest()

[Route("api/[controller]")]
[ApiController]
public class MyController : MyControllerBase
{
    [HttpGet]
    [Route("{key}")]
    public IActionResult Get(int key)
    {
        try
        {
            //do something that fails
        }
        catch (Exception e)
        {
            LogException(e);
            return InternalServerError();
        }
    }
}

public class MyControllerBase : ControllerBase
{
    public InternalServerErrorObjectResult InternalServerError()
    {
        return new InternalServerErrorObjectResult();
    }

    public InternalServerErrorObjectResult InternalServerError(object value)
    {
        return new InternalServerErrorObjectResult(value);
    }
}

public class InternalServerErrorObjectResult : ObjectResult
{
    public InternalServerErrorObjectResult(object value) : base(value)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }

    public InternalServerErrorObjectResult() : this(null)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }
}

6

当您想在MVC .Net Core中返回JSON响应时,也可以使用:

Response.StatusCode = (int)HttpStatusCode.InternalServerError;//Equals to HTTPResponse 500
return Json(new { responseText = "my error" });

这将同时返回JSON结果和HTTPStatus。我用它来将结果返回给jQuery.ajax()。


1
我不得不使用,return new JsonResult ...但否则效果很好。
Mike Taverne

5

对于aspnetcore-3.1,您也可以使用Problem()如下所示;

https://docs.microsoft.com/zh-cn/aspnet/core/web-api/handle-errors?view=aspnetcore-3.1

 [Route("/error-local-development")]
public IActionResult ErrorLocalDevelopment(
    [FromServices] IWebHostEnvironment webHostEnvironment)
{
    if (webHostEnvironment.EnvironmentName != "Development")
    {
        throw new InvalidOperationException(
            "This shouldn't be invoked in non-development environments.");
    }

    var context = HttpContext.Features.Get<IExceptionHandlerFeature>();

    return Problem(
        detail: context.Error.StackTrace,
        title: context.Error.Message);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.