我对我们向客户返回错误的方式有顾虑。
当我们得到一个错误时,我们是否通过抛出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)
}
}
或者我们把所有错误都加起来,然后发送回客户端:
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);
}
这只是一个示例代码,无论是验证错误还是服务器错误都不重要,我只是想知道最佳实践,每种方法的优点和缺点。
其中一些答案似乎是过去的遗迹。我发现下面的解决方案既简单又有效。这是在. net 6中用于从ControllerBase派生的Web API。
而不是抛出异常,你可以直接返回各种HTTP响应代码作为对象,以及一个准确的错误消息:
using Microsoft.AspNetCore.Mvc;
[ApiController]
public class MyWebApiController : ControllerBase
{
[HttpPost]
public IActionResult Process(Customer customer)
{
if (string.IsNullOrEmpty(customer.Name))
return BadRequest("Customer Name cannot be empty");
if (!Customers.Find(customer))
return NotFound("Customer does not have any account");
// After validating inputs, core logic goes here...
return Ok(customer.ID); // or simply "return Ok()" if not returning data
}
}
请在这里查看可用的错误代码列表。
至于什么时候返回错误(OP的问题),这取决于需求。在错误发生时返回错误意味着您可以避免额外处理的开销,但随后客户机必须重复调用以获取所有错误。还要考虑服务器视点,因为当发生错误时,它可能导致不希望的程序行为继续服务器端处理。
ASP。NET Web API 2确实简化了它。例如,以下代码:
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);
}
}
当没有找到该项时,返回以下内容到浏览器:
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"
}
建议:除非有灾难性错误(例如WCF Fault Exception),否则不要抛出HTTP Error 500。选择一个表示数据状态的适当HTTP状态代码。(请参阅下面的apigee链接。)
链接:
ASP中的异常处理。NET Web API (asp.net)
而且
RESTful API设计:错误怎么办?(apigee.com)
你可以在Web Api中使用自定义ActionFilter来验证模型:
public class DRFValidationFilters : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
//BadRequest(actionContext.ModelState);
}
}
public override Task OnActionExecutingAsync(HttpActionContext actionContext,
CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
});
}
public class AspirantModel
{
public int AspirantId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string AspirantType { get; set; }
[RegularExpression(@"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$",
ErrorMessage = "Not a valid Phone number")]
public string MobileNumber { get; set; }
public int StateId { get; set; }
public int CityId { get; set; }
public int CenterId { get; set; }
[HttpPost]
[Route("AspirantCreate")]
[DRFValidationFilters]
public IHttpActionResult Create(AspirantModel aspirant)
{
if (aspirant != null)
{
}
else
{
return Conflict();
}
return Ok();
}
}
}
在webApiConfig.cs中注册CustomAttribute类
config.Filters。添加(新DRFValidationFilters ());
对于那些modelstate的错误。isvalid是false,我通常发送错误,因为它是由代码抛出的。对于使用我的服务的开发人员来说,这很容易理解。我通常使用下面的代码发送结果。
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);}
这将错误以以下格式发送给客户端,基本上是一个错误列表:
[
"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)"
]