本文翻译自:Best practice to return errors in ASP.NET Web API

I have concerns on the way that we returns errors to client. 我对我们向客户返回错误的方式感到担忧。

Do we return error immediately by throwing HttpResponseException when we get an error: 当我们收到错误消息时,是否通过抛出HttpResponseException立即返回错误消息:

public void Post(Customer customer)
{if (string.IsNullOrEmpty(customer.Name)){throw new HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest) }if (customer.Accounts.Count == 0){throw new HttpResponseException("Customer does not have any account", HttpStatusCode.BadRequest) }
}

Or we accumulate all errors then send back to client: 否则我们会累积所有错误,然后发回给客户:

public void Post(Customer customer)
{List<string> errors = new List<string>();if (string.IsNullOrEmpty(customer.Name)){errors.Add("Customer Name cannot be empty"); }if (customer.Accounts.Count == 0){errors.Add("Customer does not have any account"); }var responseMessage = new HttpResponseMessage<List<string>>(errors, HttpStatusCode.BadRequest);throw new HttpResponseException(responseMessage);
}

This is just a sample code, it does not matter either validation errors or server error, I just would like to know the best practice, the pros and cons of each approach. 这只是一个示例代码,与验证错误或服务器错误无关,我只想了解最佳实践,每种方法的优缺点。


#1楼

参考:https://stackoom.com/question/j23A/在ASP-NET-Web-API中返回错误的最佳实践


#2楼

For me I usually send back a HttpResponseException and set the status code accordingly depending on the exception thrown and if the exception is fatal or not will determine whether I send back the HttpResponseException immediately. 对我而言,我通常会发回HttpResponseException并根据引发的异常来相应地设置状态代码,并且该异常是否致命,将决定我是否立即发回HttpResponseException

At the end of the day its an API sending back responses and not views, so I think its fine to send back a message with the exception and status code to the consumer. 归根结底,它的API发送回响应而不是视图,因此我认为可以将带有异常和状态代码的消息发送回消费者。 I currently haven't needed to accumulate errors and send them back as most exceptions are usually due to incorrect parameters or calls etc. 我目前不需要累积错误并将其发送回去,因为大多数异常通常是由于不正确的参数或调用等导致的。

An example in my app is that sometimes the client will ask for data, but there isnt any data available so i throw a custom noDataAvailableException and let it bubble to the web api app, where then in my custom filter which captures it sending back a relevant message along with the correct status code. 我的应用程序中的一个示例是有时客户端会请求数据,但是没有可用的数据,因此我抛出了自定义的noDataAvailableException并让其冒泡到Web api应用程序,然后在我的自定义过滤器中捕获该数据并发送回相关信息消息以及正确的状态代码。

I am not 100% sure on whats the best practice for this, but this is working for me currently so thats what im doing. 我不确定100%的最佳做法是什么,但这目前对我有用,因此我正在做什么。

Update : 更新

Since i answered this question a few blog posts have been written on the topic: 自从我回答了这个问题以来,就该主题写了一些博客文章:

http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx

(this one has some new features in the nightly builds) http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx (此文件在夜间版本中具有一些新功能) http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx

Update 2 更新2

Update to our error handling process, we have two cases: 更新我们的错误处理过程,我们有两种情况:

  1. For general errors like not found, or invalid parameters being passed to an action we return a HttpResponseException to stop processing immediately. 对于未找到的一般错误或传递给操作的无效参数,我们返回HttpResponseException以立即停止处理。 Additionally for model errors in our actions we will hand the model state dictionary to the Request.CreateErrorResponse extension and wrap it in a HttpResponseException. 此外,对于操作中的模型错误,我们会将模型状态字典传递给Request.CreateErrorResponse扩展,并将其包装在HttpResponseException中。 Adding the model state dictionary results in a list of the model errors sent in the response body. 添加模型状态字典会在响应正文中发送一个模型错误列表。

  2. For errors that occur in higher layers, server errors, we let the exception bubble to the Web API app, here we have a global exception filter which looks at the exception, logs it with elmah and trys to make sense of it setting the correct http status code and a relevant friendly error message as the body again in a HttpResponseException. 对于更高层发生的错误(服务器错误),我们让异常冒泡到Web API应用程序,这里我们有一个全局异常过滤器,用于查看异常,使用elmah记录该异常,并尝试通过设置正确的http来理解该异常。状态代码和相关的友好错误消息作为正文再次出现在HttpResponseException中。 For exceptions that we aren't expecting the client will receive the default 500 internal server error, but a generic message due to security reasons. 对于某些例外情况,我们预计客户端不会收到默认的500内部服务器错误,但由于安全原因,会收到一条通用消息。

Update 3 更新3

Recently, after picking up Web API 2, for sending back general errors we now use the IHttpActionResult interface, specifically the built in classes for in the System.Web.Http.Results namespace such as NotFound, BadRequest when they fit, if they dont we extend them, for example a notfound result with a response message: 最近,在选择了Web API 2之后,为了发送回一般错误,我们现在使用IHttpActionResult接口,特别是System.Web.Http.Results命名空间中的内置类,例如NotFound,BadRequest(如果适合),如果不能,我们扩展它们,例如带有响应消息的未找到结果:

public class NotFoundWithMessageResult : IHttpActionResult
{private string message;public NotFoundWithMessageResult(string message){this.message = message;}public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken){var response = new HttpResponseMessage(HttpStatusCode.NotFound);response.Content = new StringContent(message);return Task.FromResult(response);}
}

#3楼

ASP.NET Web API 2 really simplified it. ASP.NET Web API 2确实简化了它。 For example, the following code: 例如,以下代码:

public HttpResponseMessage GetProduct(int id)
{Product item = repository.Get(id);if (item == null){var message = string.Format("Product with id = {0} not found", id);HttpError err = new HttpError(message);return Request.CreateResponse(HttpStatusCode.NotFound, err);}else{return Request.CreateResponse(HttpStatusCode.OK, item);}
}

returns the following content to the browser when the item is not found: 找不到项目时,将以下内容返回到浏览器:

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Date: Thu, 09 Aug 2012 23:27:18 GMT
Content-Length: 51{"Message": "Product with id = 12 not found"
}

Suggestion: Don't throw HTTP Error 500 unless there is a catastrophic error (for example, WCF Fault Exception). 建议:除非发生灾难性错误(例如WCF Fault Exception),否则不要抛出HTTP Error 500。 Pick an appropriate HTTP status code that represents the state of your data. 选择一个适当的HTTP状态代码来表示您的数据状态。 (See the apigee link below.) (请参阅下面的apigee链接。)

Links: 链接:

  • Exception Handling in ASP.NET Web API (asp.net) and ASP.NET Web API (asp.net)和
  • RESTful API Design: what about errors? RESTful API设计:错误呢? (apigee.com) (apigee.com)

#4楼

You can throw a HttpResponseException 您可以抛出HttpResponseException

HttpResponseMessage response = this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "your message");
throw new HttpResponseException(response);

#5楼

It looks like you're having more trouble with Validation than errors/exceptions so I'll say a bit about both. 看来您在验证方面遇到的麻烦比错误/异常要多,因此我将同时介绍两者。

Validation 验证方式

Controller actions should generally take Input Models where the validation is declared directly on the model. 控制器操作通常应采用输入模型,其中直接在模型上声明验证。

public class Customer
{ [Require]public string Name { get; set; }
}

Then you can use an ActionFilter that automatically sends valiation messages back to the client. 然后,您可以使用ActionFilter ,该过滤器自动将验证消息发送回客户端。

public class ValidationActionFilter : ActionFilterAttribute
{public override void OnActionExecuting(HttpActionContext actionContext){var modelState = actionContext.ModelState;if (!modelState.IsValid) {actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);}}
}

For more information about this check out http://ben.onfabrik.com/posts/automatic-modelstate-validation-in-aspnet-mvc 有关此的更多信息,请访问http://ben.onfabrik.com/posts/automatic-modelstate-validation-in-aspnet-mvc

Error handling 错误处理

It's best to return a message back to the client that represents the exception that happened (with relevant status code). 最好将表示发生的异常的消息返回给客户端(带有相关的状态代码)。

Out of the box you have to use Request.CreateErrorResponse(HttpStatusCode, message) if you want to specify a message. 如果要指定消息Request.CreateErrorResponse(HttpStatusCode, message)必须直接使用Request.CreateErrorResponse(HttpStatusCode, message) However, this ties the code to the Request object, which you shouldn't need to do. 但是,这会将代码与Request对象联系在一起,您不需要这样做。

I usually create my own type of "safe" exception that I expect the client would know how to handle and wrap all others with a generic 500 error. 我通常会创建自己的“安全”异常类型,我希望客户端会知道如何处理和包装所有其他带有通用500错误的异常。

Using an action filter to handle the exceptions would look like this: 使用动作过滤器来处理异常如下所示:

public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{public override void OnException(HttpActionExecutedContext context){var exception = context.Exception as ApiException;if (exception != null) {context.Response = context.Request.CreateErrorResponse(exception.StatusCode, exception.Message);}}
}

Then you can register it globally. 然后,您可以在全球进行注册。

GlobalConfiguration.Configuration.Filters.Add(new ApiExceptionFilterAttribute());

This is my custom exception type. 这是我的自定义异常类型。

using System;
using System.Net;namespace WebApi
{public class ApiException : Exception{private readonly HttpStatusCode statusCode;public ApiException (HttpStatusCode statusCode, string message, Exception ex): base(message, ex){this.statusCode = statusCode;}public ApiException (HttpStatusCode statusCode, string message): base(message){this.statusCode = statusCode;}public ApiException (HttpStatusCode statusCode){this.statusCode = statusCode;}public HttpStatusCode StatusCode{get { return this.statusCode; }}}
}

An example exception that my API can throw. 我的API可能引发的示例异常。

public class NotAuthenticatedException : ApiException
{public NotAuthenticatedException(): base(HttpStatusCode.Forbidden){}
}

#6楼

For those errors where modelstate.isvalid is false, I generally send the error as it is thrown by the code. 对于那些那些modelstate.isvalid为false的错误,我通常会发送代码抛出的错误。 Its easy to understand for the developer who is consuming my service. 对于使用我的服务的开发人员而言,这很容易理解。 I generally send the result using below code. 我通常使用以下代码发送结果。

     if(!ModelState.IsValid) {List<string> errorlist=new List<string>();foreach (var value in ModelState.Values){foreach(var error in value.Errors)errorlist.Add( error.Exception.ToString());//errorlist.Add(value.Errors);}HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest,errorlist);}

This sends the error to the client in below format which is basically a list of errors: 这会将错误以以下格式发送给客户端,该格式基本上是错误列表:

    [  "Newtonsoft.Json.JsonReaderException: **Could not convert string to integer: abc. Path 'Country',** line 6, position 16.\r\n
at Newtonsoft.Json.JsonReader.ReadAsInt32Internal()\r\n
at Newtonsoft.Json.JsonTextReader.ReadAsInt32()\r\n
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter, Boolean inArray)\r\n
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)","Newtonsoft.Json.JsonReaderException: **Could not convert string to integer: ab. Path 'State'**, line 7, position 13.\r\n
at Newtonsoft.Json.JsonReader.ReadAsInt32Internal()\r\n
at Newtonsoft.Json.JsonTextReader.ReadAsInt32()\r\n
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter, Boolean inArray)\r\n
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)"]

在ASP.NET Web API中返回错误的最佳实践相关推荐

  1. (四)Asp.net web api中的坑-【api的返回值】

    (四)Asp.net web api中的坑-[api的返回值] 原文:(四)Asp.net web api中的坑-[api的返回值] void无返回值 IHttpActionResult HttpRe ...

  2. ASP.NET Web API中的Controller

    虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...

  3. 监控系统简介(二):使用 App Metrics 在 ASP.NET Web API 中记录指标

    回顾 在<监控系统简介:使用 Prometheus 与 Grafana>一文中,我们了解了什么是监控系统,Prometheus 这一监控工具及它提供的数据类型.PromQL 以及 Graf ...

  4. ASP.NET Web API中的参数绑定总结

    ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...

  5. 【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie

    5.5 HTTP Cookies in ASP.NET Web API 5.5 ASP.NET Web API中的HTTP Cookie 本文引自:http://www.asp.net/web-api ...

  6. ASP.NET Web API中实现版本的几种方式

    在ASP.NET Web API中,当我们的API发生改变,就涉及到版本问题了.如何实现API的版本呢? 1.通过路由设置版本 最简单的一种方式是通过路由设置,不同的路由,不同的版本,不同的contr ...

  7. 利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理

    在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在 ...

  8. ASP.NET Web API中实现版本

    一般来说,api 接口是提供给其他系统或是其他公司使用,不能随意频繁的变更.然而,需求和业务不断变化,接口和参数也会发生相应的变化.如果直接对原来的接口进行修改,势必会影响线其他系统的正常运行.这就必 ...

  9. ASP.NET Web API中的返回值

    本文将Web API中常用的返回值罗列了一下,如需要进一步详细了解,请点击这篇文章 返回值 继承接口 描述 void 无 返回http状态码204,告诉客户端此请求没有返回值 Json<T> ...

最新文章

  1. python3 lambda表达式
  2. CSS基础(part15)--元素的隐藏与显示
  3. Net 5.0 快速开发框架 YC.Boilerplate--框架介绍
  4. Mac备忘录笔记教学——强大的内置笔记软件
  5. spring基础——<bean>scope属性
  6. libvirt/qemu特性之快照
  7. 编程珠玑---第二章 啊哈!算法
  8. 2013国家二级c语言上机考试点了编译并运行出现黑框闪退,2013年计算机二级C语言上机试题及解析2...
  9. string的一些常见函数
  10. openssl生成Windows证书
  11. Hive-3.1.3安装配置运行
  12. 无源蜂鸣器c语言编程,无源蜂鸣器+LED
  13. SoX 音频处理工具使用方法
  14. ARM Coresight
  15. 读取手机内存和SD卡的空间大小
  16. Miniconda在服务器上的安装与使用
  17. 前端异步请求解决方案
  18. 2020医科大7月计算机考试,2020年首都医科大学网络考试的一些经验
  19. 房产管理系统用户权限管理
  20. 2019年4月1日起——出入境证件“全国通办”,可在支付宝预约港澳台签注等8项服务

热门文章

  1. C#.NET如何将cs文件编译成dll文件 exe文件 如何调用dll文件
  2. javascript之复习(框架里的方法们)
  3. 【算法学习笔记】16.暴力求解法04 回溯法03 剪枝法 带宽
  4. [Linux] vimdiff 快速比较和合并少量文件
  5. 【转】更改navigationController push和pop界面切换动画
  6. word2010 同时打开多个文档的解决办法
  7. Java并发编程的艺术 记录(三)
  8. oracle数据库导入gson包
  9. java 学习第三篇if判断
  10. js 设计模式学习(1)