[英]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 问题
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. 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. 对于您而言,我认为抛出
HttpResponseException
的HttpResponseMessage
包含异常消息将起作用。 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.