cuo*_*gle 364 c# rest asp.net-web-api
我对我们向客户返回错误的方式感到担忧.
当我们收到错误时,我们通过抛出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)
}
}
Run Code Online (Sandbox Code Playgroud)
或者我们累积所有错误然后发送回客户端:
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);
}
Run Code Online (Sandbox Code Playgroud)
这只是一个示例代码,无论是验证错误还是服务器错误都无关紧要,我只想了解最佳实践,每种方法的优缺点.
gdp*_*gdp 282
对我来说,我通常会发回一个HttpResponseException
并根据抛出的异常相应地设置状态代码,如果异常是致命的,将决定我是否HttpResponseException
立即发回.
在一天结束时,它会发送回应用而不是视图的API,因此我认为可以将带有异常和状态代码的消息发送给消费者.我目前不需要累积错误并将其发回,因为大多数异常通常是由于不正确的参数或调用等.
在我的应用程序的一个例子是,有时客户会要求数据,但心不是任何可用的数据,所以我抛出一个自定义noDataAvailableException,让它泡到Web API的应用程序,其中,然后在我的自定义过滤器捕获它发回相关消息以及正确的状态代码.
我不是百分之百确定这是什么最好的做法,但这对我来说是有用的,所以我正在做什么.
更新:
由于我回答了这个问题,因此在这个主题上写了几篇博文:
http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
(这个在夜间版本中有一些新功能) http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
更新2
更新到我们的错误处理过程,我们有两种情况:
对于未找到的常规错误或传递给操作的无效参数,我们返回HttpResponseException以立即停止处理.另外,对于我们的操作中的模型错误,我们将模型状态字典交给Request.CreateErrorResponse
扩展并将其包装在HttpResponseException中.添加模型状态字典会生成响应正文中发送的模型错误列表.
对于更高层中发生的错误,服务器错误,我们让异常气泡到Web API应用程序,这里我们有一个全局异常过滤器查看异常,用elmah和trys记录它以理解它设置正确的http状态代码和相关的友好错误消息在HttpResponseException中再次作为正文.对于我们不期望的异常,客户端将收到默认的500内部服务器错误,但由于安全原因会收到通用消息.
更新3
近日,拿起网页API 2,对于发回的一般错误后,我们现在使用的IHttpActionResult接口,特别是内置类在System.Web.Http.Results命名空间,如NOTFOUND,错误请求当他们配合,如果他们不我们扩展它们,例如带有响应消息的未发现结果:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
Man*_*ain 174
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);
}
}
Run Code Online (Sandbox Code Playgroud)
当找不到该项时,将以下内容返回给浏览器:
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"
}
Run Code Online (Sandbox Code Playgroud)
建议:除非发生灾难性错误(例如,WCF故障异常),否则不要抛出HTTP错误500.选择一个代表数据状态的相应HTTP状态代码.(见下面的apigee链接.)
链接:
Dan*_*tle 74
看起来你在验证方面遇到的问题多于错误/异常,所以我会对两者都说一点.
验证
控制器操作通常应采用输入模型,其中验证直接在模型上声明.
public class Customer
{
[Require]
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用ActionFilter
自动将valiation消息发送回客户端.
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
有关此检查的更多信息,请访问http://ben.onfabrik.com/posts/automatic-modelstate-validation-in-aspnet-mvc
错误处理
最好将消息返回给客户端,代表发生的异常(带有相关的状态代码).
Request.CreateErrorResponse(HttpStatusCode, message)
如果要指定消息,则必须使用开箱即用.但是,这会将代码绑定到Request
对象上,您不应该这样做.
我通常创建自己的"安全"异常类型,我希望客户端知道如何处理并用通用500错误包装所有其他异常.
使用操作过滤器来处理异常将如下所示:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以在全球注册它.
GlobalConfiguration.Configuration.Filters.Add(new ApiExceptionFilterAttribute());
Run Code Online (Sandbox Code Playgroud)
这是我的自定义异常类型.
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; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的API可以抛出的示例异常.
public class NotAuthenticatedException : ApiException
{
public NotAuthenticatedException()
: base(HttpStatusCode.Forbidden)
{
}
}
Run Code Online (Sandbox Code Playgroud)
tar*_*nov 36
你可以抛出一个HttpResponseException
HttpResponseMessage response =
this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "your message");
throw new HttpResponseException(response);
Run Code Online (Sandbox Code Playgroud)
Mic*_*ick 22
对于Web API 2,我的方法始终返回IHttpActionResult,所以我使用...
public IHttpActionResult Save(MyEntity entity)
{
....
return ResponseMessage(
Request.CreateResponse(
HttpStatusCode.BadRequest,
validationErrors));
}
Run Code Online (Sandbox Code Playgroud)
Fab*_*rts 17
如果您使用的是ASP.NET Web API 2,最简单的方法是使用ApiController Short-Method.这将导致BadRequestResult.
return BadRequest("message");
Run Code Online (Sandbox Code Playgroud)
欢迎来到 2022 年!现在我们在 .NET 中有其他答案(自 ASP.NET Core 2.1 起)。看这篇文章:Using the ProblemDetails Class in ASP.NET Core Web API,其中作者解释了以下最佳实践:
ProductDetails
作为一个预告,如果我们使用和 多个错误,JSON 输出将如下所示:
小智 5
您可以在 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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在 webApiConfig.cs 中注册 CustomAttribute 类 config.Filters.Add(new DRFValidationFilters());
归档时间: |
|
查看次数: |
461379 次 |
最近记录: |