简体   繁体   English

从Web API方法返回异常

[英]Returning the exception from a web api method

I have the method below in my webapi. 我的webapi中有以下方法。 I want to be able to pass the exception to post man and see the error. 我希望能够将异常传递给post man并查看错误。 I tried using "return BadRequest(ex.Message);" 我尝试使用“返回BadRequest(ex.Message);” and I got errors because of the return type of the method. 并且由于该方法的返回类型而出现错误。

How can I correct this such that I can return the actual error message if any? 我该如何纠正它,以便我可以返回实际的错误消息(如果有)?

        // 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;
        }

There are a few issues with what you are doing. 您的操作存在一些问题。 Let's go over them firstly and then we will go over a better approach. 首先让我们研究它们,然后我们将讨论一种更好的方法。

Issues 问题

  1. Do not catch an exception of type Exception and then tell the client their request is a bad request. 不要捕获Exception类型的Exception ,然后告诉客户端他们的请求是错误的请求。 If you have a DivideByZeroException , db not found exception, or InvalidOperationException or any other exception, you will tell the client their request is bad. 如果您有DivideByZeroException ,db not found异常, InvalidOperationException或任何其他异常,则将告诉客户端他们的请求是错误的。 This will clearly not be true. 这显然是不正确的。
  2. Your API is asking the client to provide you with a string for a category. 您的API要求客户端为您提供类别的字符串。 So long as they provide it, even if it is "xaoudis garbage", they have done what they are supposed to do: Provide you with a string. 只要他们提供了它,即使它是“ xaoudis垃圾”,他们也应该做他们应该做的事情:为您提供一个字符串。 Now it is your responsibility to do your best and provide them with a result. 现在,您有责任尽力并为他们提供结果。 The result can be a list of items in that category or an error. 结果可以是该类别中的项目列表或错误。

Returning a Response from Web API 从Web API返回响应

Returning a domain object (or a DTO) is fine but if you want to have a finer level of control over the response then use HttpResponseMessage . 返回域对象(或DTO)很好,但是如果您想对响应进行更好的控制,请使用HttpResponseMessage Here is an examplef (please read the comments in code for more information): 这是一个examplef(请阅读代码中的注释以获取更多信息):

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);
    }
}

Web API 2 Web API 2

With Web API 2, you can do it like this which is much easier and cleaner. 使用Web API 2,您可以像这样更轻松,更清洁地做到这一点。 Please change the code as per your requirements. 请根据您的要求更改代码。

public IHttpActionResult Get(string category)
{
    try
    {
        // code...

        return 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 InternalServerError();
    }
}

There are probably some other ways to do this (I don't claim to be an ASP.Net Core expert) but I have solved this problem the following way. 可能还有其他方法可以做到这一点(我不声称自己是ASP.Net Core专家),但是我已经通过以下方法解决了这个问题。 First, define a custom exception class. 首先,定义一个自定义异常类。 The purpose is that you can actually throw this without regard to any controller method return type. 目的是实际上可以在不考虑任何控制器方法返回类型的情况下抛出此错误。 Also, throwing exceptions makes control flow a lot more structured. 同样,抛出异常会使控制流更加结构化。

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;
    }
}

Then define a custom ExceptionFilterAttribute. 然后定义一个自定义ExceptionFilterAttribute。 Please note that this copy/pasted snippet does a bit more than what you have been asking for. 请注意,这个复制/粘贴的片段比您所要求的要多。 Eg depending on the development vs. production it will include the entire stack trace of the exception (of any exception actually, not just CustomApiException). 例如,根据开发还是生产,它将包括异常的整个堆栈跟踪(实际上是任何异常,而不仅仅是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;
    }
}

Finally, add the custom ExceptionFilterAttribute to the global ConfigureServices method. 最后,将自定义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));
            });
    }

    // ...
}

It's a little bit of work but only one-off work, and pretty powerful once you have added it. 这只是一点点工作,但只有一次性的工作,添加后功能非常强大。 If I remember correctly, my solution is based on this MS page Exception Handling . 如果我没记错的话,我的解决方案是基于此MS页面的Exception Handling This may be of help if you have further questions. 如果您还有其他问题,这可能会有所帮助。

For you case, I think throw out the HttpResponseException with a HttpResponseMessage contains the exception message would work. 对于您而言,我认为抛出HttpResponseExceptionHttpResponseMessage包含异常消息将起作用。 Flowing code snippet has been tested my end. 流畅的代码段已通过测试。

    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);
        }
    }

For more information about how to handle exception in WebAPI flow, refer to this official guide. 有关如何在WebAPI流中处理异常的更多信息,请参阅官方指南。 Hope it is helpful for you. 希望对您有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从WEB API Controller返回异步方法中的Void - Returning Void in Async method from WEB API Controller 从Web API控制器方法返回单个对象和字符串 - Returning single object and string from web api controller method 从 web api 返回 zip 文件 - Returning a zipfile from a web api 断言Web API方法是否返回特定类型? - Assert Web API Method is returning a specific type? 从Web API返回Entity Framework类会引发“未能序列化内容类型的响应正文”异常 - Returning Entity Framework class from Web API throws “failed to serialize the response body for content type” exception Web Api在异步方法上引发异常 - Web Api throwing Exception on async method HttpContent.ReadAsAsync 方法未从 Web API 调用返回正确的值 - HttpContent.ReadAsAsync method not returning correct value from a Web API call 如何将错误消息从 Web API 控制器的 HttpPost 异步方法返回任务传递给客户端<Type> ? - How to pass error message to client from Web API controller's HttpPost async method returning Task<Type>? Post方法返回405方法不允许在Angular 8 web api项目中使用 - Post method returning 405 Method not allowed in Angular 8 web api project 从Web API返回时Zip损坏了吗? - Corrupted Zip while returning from Web API?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM