处理在ApiController上执行POST时发送的id的最佳实践?

时间:2013-02-26 12:22:52

标签: c# asp.net asp.net-web-api

考虑以下两种POST方案:

  1. POST /localhost/api/ - 插入实体,返回200
  2. POST /localhost/api/1324 - 错误请求,返回400
  3. 处理场景2的最佳方法是什么?

    我什么都不做,并假设使用我的API的开发人员会理解这是错的?我是否在POST方法中添加代码来处理这个并告诉他们这是一个错误的请求?

    我意识到返回一个错误的请求可能是最好的事情,这是我最终实现的,但我觉得可能有更好的方法来实现这个我还没有发现。

    我的当前代码如下:

    [HttpPost]
    public HttpResponseMessage Post(MyEntity entity) {
      if(entity.Id != null)
          throw new HttpResponseException(HttpStatusCode.BadRequest);
    
      MyEntity saved = repository.Insert(entity);
    
      HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, saved);
      response.Headers.Location = new Uri(Request.RequestUri, new Uri(saved.Id.ToString(), UriKind.Relative));
    
      return response;
    }
    
    // Prevents any attempt to POST with a Guid in the url
    [HttpPost]
    public void Post(Guid Id) {
      throw new HttpResponseException(HttpStatusCode.BadRequest);
    }
    

    谢谢!

3 个答案:

答案 0 :(得分:3)

你的行为似乎有效。虽然我对是否会这么做有疑问。

<强>校正

我说过

  

如果您没有实现此附加方法,那么路由   会失败,并且通常会返回404.我会的   很想留下这种行为。

但你是对的:

要使其按上述方式运行,即默认为404,您需要以下路线配置:

       config.Routes.MapHttpRoute(
            name: "DefaultCollectionApi",
            routeTemplate: "api/{controller}",
            defaults: new { },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) }
            );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new {  },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get, HttpMethod.Put, HttpMethod.Delete) }
            );

稍微改善现有方法

但是,如果您确实觉得需要开始监管动词和路由的组合,那么将此逻辑移动到ActionFilterAttribute中可能是值得的。

如果你在顶部添加这条路线,那么它将是en 假设您按照约定对所有路由使用"id",您可以快速组合一个过滤器,在RouteValues中使用id键查找值,并引发400异常。

public class ValidVerbAndRouteAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        object id;
        if (actionExecutedContext.ActionContext.ActionArguments.TryGetValue("id", out id) &&
            actionExecutedContext.Request.Method == HttpMethod.Post)
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    }
} 

答案 1 :(得分:2)

您目前的处理方式似乎是正确的。它是标准输入数据验证,如果此验证在RESTful条款中失败,则400是正确的状态代码。

答案 2 :(得分:1)

你想要这样做的方式是正确的,但如果你愿意,还有另一种选择方式。您可以配置路由并声明应该调用具体操作,而不是指定具有签名的操作,如

[HttpPost]
public HttpResponseMessage PostEntity([FromBody]MyEntity entity) {...}

将使用此操作的任何其他签名进行调用,这将导致异常。

路线:

            config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional });

对于异常处理,我建议使用一个异常过滤器,它包含一组异常类型的映射及其根据您的喜好进行的HttpStatusCode表示。