【问题标题】:Asp.Net Web Api - Returning 404 for IEnumerable<T> Get When nullAsp.Net Web Api - 为 IEnumerable<T> 返回 404 获取时为空
【发布时间】:2012-10-02 16:51:28
【问题描述】:

我正在使用 Asp.Net Web Api 的发布版本创建一个 API。如果没有找到结果,我正在尝试传回正确的响应代码 (404)。

首次获取版本(抛出多个枚举错误):

public IEnumerable<MyObjectType> Get(int id, string format)
{
    var db = new DbEntities();

    var result = db.pr_ApiSelectMyObjectType(store, id, format).AsEnumerable();
    if (result.Any())
    {
        return result;
    }
    var response = new HttpResponseMessage(HttpStatusCode.NotFound) 
        { Content = new StringContent("Unable to find any results") };
    throw new HttpResponseException(response);
}

第二次获取版本(结果永远不会为空,所以总是返回 200):

public IEnumerable<MyObject> Get(int id, string format)
{
    var db = new DbEntities();

    var result = db.pr_ApiSelectMyObjectType(store, id, format);
    if (result == null)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NoContent) 
            { Content = new StringContent("Unable to find any results") };
        throw new HttpResponseException(response);
    }
    return result.AsEnumerable();
}

如果没有找到结果,我该如何回传 404?我知道我可以使用一个列表,但我有一个自定义 csv 媒体类型格式化程序,它只适用于 IEnumerable 类型,所以我更愿意坚持使用它。

【问题讨论】:

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


    【解决方案1】:

    更好的方法是在动作过滤器级别捕获null,定义一个具有全局范围的动作过滤器,并从中抛出异常404:

    public class NullFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            var response = actionExecutedContext.Response;
    
            object responseValue;
            bool hasContent = response.TryGetContentValue(out responseValue);
    
            if (!hasContent)
                throw new HttpResponseException(HttpStatusCode.NotFound);
        }
    }
    

    通过这种方式,您无需在操作中使用Any,代码会更简单:

    public IEnumerable<MyObjectType> Get(int id, string format)
    {
        using (db = new DbEntities())
        {
           return db.pr_ApiSelectMyObjectType(store, id, format)
                    .AsEnumerable();
        }
    }
    

    【讨论】:

      【解决方案2】:

      将结果转换为列表可能是最简单的,显然可以多次枚举:

      var result = db.pr_ApiSelectMyObjectType(store, id, format).ToList();
      if (!result.Any())
      {
          ...
      }
      

      当然,这意味着将整个查询具体化......但大概你最终会在某个时候这样做。

      【讨论】:

      • 1.我相信使用result.Count != 0 应该更快,因为它不会使用EnumerableAny 扩展方法,它创建一个迭代器块而是一个列表的属性。 2. 使用 Web API v2 和 OData,您可能希望返回 IQueryable 而不是 List(或 IEnumerable)。
      • @gdoron:我相信Any() 无论如何都针对ICollection&lt;T&gt; 实现进行了优化,但在过滤的情况下,它可能比使用Count() 更有效率很多序列。
      【解决方案3】:

      在你的情况下,而不是返回:

      return result.AsEnumerable();
      

      你可以返回 null:

      return null;
      

      从调用函数中,您检查返回的结果类似于:

      var myObject = Get(id, format);
      if (myObject == null)
          return NotFound(myObject);
      else
          return Ok(myObject);
      

      如果Get函数找不到记录,你会得到404 not found。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-18
        • 2015-04-26
        • 2010-09-27
        • 1970-01-01
        • 2016-08-23
        • 2014-05-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多