代码之家  ›  专栏  ›  技术社区  ›  user743382

当从Web API方法返回IQueryable时,如何确保错误状态代码?

  •  0
  • user743382  · 技术社区  · 6 年前

    我正在通过 Microsoft.AspNetCore.OData 包裹。成功案例是有效的,但我注意到当 IQueryable<T> 返回成功,但执行失败,我没有得到一个像样的错误消息。相反,我得到一个截断的结果:

    {"@odata.context":"https://localhost:44300/odata/$metadata#Documents","value":[
    

    我的控制器没有什么特别之处:

    public class DocumentsController : ODataController
    {
        Db.Context Context { get; }
    
        public DocumentsController(Db.Context context)
        {
            Context = context;
        }
    
        [EnableQuery]
        public ActionResult<IQueryable<Document>> Get()
        {
            return Context.Documents;
        }
    }
    

    这个问题不是OData特有的:一个普通的 ControllerBase -派生控制器返回 IQueryable<Document> 行为方式相同(除非只有 [ )然而,OData的背景可能会排除一些可能的解决方案。

    我理解发生这种情况的原因:已经开始发送串行结果;无法及时返回以取消发送并发送错误响应。

    我还理解,在一般情况下,阻止不是一个真正的选择:当发送许多项目时,除了最后一个项目之外,其他所有项目都可能在没有任何问题的情况下发送,并且最后一个项目可能会引发一些异常,因此在一般情况下阻止它需要缓冲完整的结果。

    但是,至少应该可以处理在 可查询 s返回其第一个结果。这将涵盖最严重的错误,其中良好的异常消息对调试非常有帮助:数据库脱机、数据库模式与预期不匹配等。

    我该怎么做呢?

    2 回复  |  直到 6 年前
        1
  •  0
  •   Ihar Yakimush    6 年前

    您可以直接在控制器中调用查询选项,而不是使用[queryable]属性。它将允许您执行所需的任何异常处理,并在需要时生成自定义响应。

    为此,请向Controller方法添加OdataQueryOptions参数。在这种情况下,您不需要[queryable]属性。更多细节 https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options#invoking-query-options-directly

        2
  •  0
  •   user743382    6 年前

    我可以创建一个自定义 IEnumerable<T> 包含另一个 IEnumerable<t> ,然后立即呼叫 .GetEnumerator().MoveNext() 施工时,注意保存枚举器和 MoveNext() 反应。然后,什么时候 我的 GetEnumerator() 第一次调用时,我会返回一个包装器来包装保存的枚举器。当其 MOVENTXEL() 第一次调用时,我返回保存的布尔值。其他用法则直接用于包装的可枚举枚举器和包装的枚举器。我将节省代码,因为实现几乎是微不足道的。

    棘手的部分是找到合适的点来包装可查询的内容。它需要在应用了URL中的任何查询修饰符之后。这里有两个主要选项:

    1. 忘掉 EnableQueryAttribute . 相反,正如我所说,我可以 ODataQueryOptions<Document> 参数并直接应用查询修饰符。因为在修改查询之后我仍然处于控制状态,所以我可以将它包装在自定义的可枚举中。
    2. 子类 启用查询属性 并覆盖其 OnResultExecuting(ResultExecutingContext context) 方法。那么,我可以检查一下 context.Result is ObjectResult 如果有的话,如果 objectResult.Value IEnumerable<t> . 如果两者都是正确的,那么我可以将结果包装起来。

      这种方法的一个变种是 OnResultExecuting 单独地 ActionFilterAttribute 导数,但对我来说,把它们放在同一类中更有意义。

    在这两种情况下,我都必须处理我没有得到 IQuerable<Document> 我可能得到一个 IQueryable<SomeWrapperAround<Document>> 相反。处理起来很容易。 dynamic 似乎这会让它变得异常简单:只需创建 object Wrap(object o) => o object Wrap<T>(IQueryable<T> queryable) => new EnumerableWrapper<T>(queryable) 重载并让运行时找出要调用的方法,但不幸的是 SomeWrapperAround 可以是OData内部类,其中 动态 不喜欢。人工思考仍然不难。