从web api方法返回异常

时间:2017-08-30 01:28:15

标签: c# asp.net-web-api

我的webapi中有以下方法。我希望能够将异常传递给post man并查看 错误。我尝试使用"返回BadRequest(ex.Message);"由于方法的返回类型,我得到了错误。

如何更正此问题,以便我可以返回实际的错误消息?

        // GET api/Articles/News
        public IEnumerable<ArticlesDto> Get(string category)
        {
            IEnumerable<ArticlesDto> articlesByCategory = null;
            try
            {
                if (category == null)
                {

                }

               articlesByCategory = _articlesrepository.Find(category);               
            }
            catch(Exception ex)
            {
                 return BadRequest(ex.Message);
            }

            return articlesByCategory;
        }

3 个答案:

答案 0 :(得分:2)

您正在做的事情存在一些问题。让我们首先回顾一下,然后我们将采用更好的方法。

<强>问题

  1. 不要捕获类型static IEnumerable<T> OrderByEnumerable<T>(this IEnumerable<T> data, IEnumerable<string> data2) { return data.Zip(data2, (x, y) => // } 的异常,然后告诉客户端他们的请求是一个错误的请求。如果您有Exception,db not found异常,或DivideByZeroException或任何其他异常,您将告诉客户端他们的请求是坏的。这显然不是真的。
  2. 您的API要求客户为您提供类别的字符串。只要他们提供它,即使它是&#34; xaoudis垃圾&#34;,他们已经做了他们应该做的事情:为你提供一个字符串。现在,您有责任尽力并为他们提供结果。结果可以是该类别中的项目列表或错误。
  3. 从Web API返回响应

    返回域对象(或DTO)很好,但如果您希望对响应进行更精细的控制,则使用InvalidOperationException。这是一个examplef(请阅读代码中的注释以获取更多信息):

    HttpResponseMessage

    Web API 2

    使用Web API 2,您可以这样做,这样更容易,更清洁。请根据您的要求更改代码。

    public HttpResponseMessage Get(string category)
    {
        // Step 1: First check the obvious issues
        if (string.IsNullOrWhiteSpace(category))
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    
        try
        {
            // The client has sent us a category. Now we have to do our best to 
            // satisfy the request.
    
            // Step 2: Optional Step: First check to see if we have the category
            string cat = _categoryRepository.Get(category);
            if (string.IsNullOrWhiteSpace(cat))
            {
                var message = new HttpResponseMessage(HttpStatusCode.NotFound);
                message.Content = new StringContent($"The category with the name {category} was not found.");
                throw new HttpResponseException(message);
            }
    
            // Step 3: Category exists so let's return the products
            IEnumerable<ArticlesDto> articlesByCategory = _articlesrepository.Find(category);
    
            // Even if the list is empty, we can still return it to tell
            // the client 0 items were found
            // for the category. 
            return Request.CreateResponse(HttpStatusCode.OK, articlesByCategory);
        }
        catch (Exception ex)
        {
            // Something went wrong on our side (NOT the client's fault). So we need to:
            // 1. Log the error so we can troubleshoot it later
            // 2. Let the client know it is not their fault but our fault.
            return Request.CreateResponse(HttpStatusCode.InternalServerError);
        }
    }
    

答案 1 :(得分:0)

可能有其他一些方法可以做到这一点(我不是自称是ASP.Net核心专家),但我已经通过以下方式解决了这个问题。首先,定义一个自定义异常类。目的是你可以实际抛出,而不考虑任何控制器方法返回类型。此外,抛出异常会使控制流更加结构化。

public class CustomApiException : Exception
{
    /// <summary>
    /// Optional application-specific error code returned to the client.
    /// </summary>
    public int? ApplicationErrorCode { get; private set; } = null;

    /// <summary>
    /// HTTP status code returned to the client.
    /// </summary>
    public HttpStatusCode HttpStatusCode { get; private set; } = HttpStatusCode.BadRequest;

    public CustomApiException() : base() { }
    public CustomApiException(string message) : base(message) { }

    public CustomApiException(string message, HttpStatusCode httpStatusCode) : base(message)
    {
        HttpStatusCode = httpStatusCode;
    }

    public CustomApiException(string message, HttpStatusCode httpStatusCode, int? applicationErrorCode) : base(message)
    {
        HttpStatusCode = httpStatusCode;
        ApplicationErrorCode = applicationErrorCode;
    }

    public CustomApiException(string message, int? applicationErrorCode) : base(message)
    {
        ApplicationErrorCode = applicationErrorCode;
    }
}

然后定义自定义ExceptionFilterAttribute。请注意,此复制/粘贴代码段的功能比您要求的要多一些。例如。根据开发与生产的不同,它将包含异常的整个堆栈跟踪(实际上是任何异常,而不仅仅是CustomApiException)。

// todo: turn into async filter.
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
    private readonly ILogger<ApiExceptionFilterAttribute> _logger;
    private readonly IHostingEnvironment _env;

    public ApiExceptionFilterAttribute(ILogger<ApiExceptionFilterAttribute> logger, IHostingEnvironment env)
    {
        _logger = logger;
        _env = env;
    }

    public override void OnException(ExceptionContext context)
    {
        _logger.LogError(new EventId(0), context.Exception, context.Exception.Message);

        dynamic errObject = new JObject();
        HttpStatusCode statusCode = HttpStatusCode.InternalServerError; // use 500 unless the API says it's a client error

        if (context.Exception.GetType() == typeof(CustomApiException))
        {
            CustomApiException customEx = (CustomApiException)context.Exception;
            if (customEx.ApplicationErrorCode != null) errObject.errorCode = customEx.ApplicationErrorCode;
            errObject.errorMessage = customEx.Message;
            statusCode = customEx.HttpStatusCode;
        }

        if (_env.IsDevelopment())
        {
            errObject.errorMessage = context.Exception.Message;
            errObject.type = context.Exception.GetType().ToString();
            errObject.stackTrace = context.Exception.StackTrace;
        }

        JsonResult result = new JsonResult(errObject);
        result.StatusCode = (int?)statusCode;
        context.Result = result;
    }
}

最后,将自定义ExceptionFilterAttribute添加到全局ConfigureServices方法。

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        //...

        // Add framework services.
        services.AddMvc(options =>
            {
                options.Filters.Add(typeof(ApiExceptionFilterAttribute));
            });
    }

    // ...
}

这是一些工作,但只有一次性工作,并且一旦你添加它就非常强大。如果我没记错的话,我的解决方案就是基于这个MS页面Exception Handling。如果您有其他问题,这可能会有所帮助。

答案 2 :(得分:0)

对于你的情况,我认为抛出HttpResponseException HttpResponseMessage包含异常消息可行。流动的代码片段已经过我的测试。

    public IEnumerable<string> Get()
    {
        try
        {
            throw new InvalidOperationException("Invalid Operation");
        }
        catch(Exception ex)
        {
            var res = new HttpResponseMessage(HttpStatusCode.InternalServerError);
            res.Content = new StringContent(ex.Message);
            throw new HttpResponseException(res);
        }
    }

有关如何在WebAPI流程中处理异常的更多信息,请参阅this官方指南。希望它对你有所帮助。

相关问题