可以从 Http 请求主体发布 ODataQueryOptions 吗?

2024-04-10

我正在实现一个 Web API 接口来支持一些相当复杂的查询来运行它,并且遇到了最大请求 URI 长度的问题。

我的 Web API 方法的定义如下所示(使用 Automapper 执行 DTO 投影):

public IQueryable<ReportModel> Get(ODataQueryOptions<Report> queryOptions)
{
     var query = DbContext.Query<Report>();

     return (queryOptions.ApplyTo(query) as IQueryable<Report>).WithTranslations().Project(MappingEngine).To<ReportModel>().WithTranslations();
}

我的请求由动态构建的 OData 查询组成,其中包括可能大量的“Field eq Id”过滤器,这些过滤器被捕获到 ODataQueryOptions 参数中,然后应用于 IQueryable 数据库上下文。例如:

http://example.com/api/Report?$filter=(Field1+eq+1%20or%20Field1+eq+5%20or%20Field1+eq+10%20or%20Field1+eq+15...

一旦请求 URI 的长度达到一定限制,就会出现此问题。任何 URI 长度超过该限制的请求都会导致 404 错误。经过一些测试,此限制似乎在 2KB 范围内(具有 2065 个字符的 URI 工作正常,而具有 2105 个字符的 URI 在 Chrome、IE 或 FF 中则失败)。

对此的简单解决方案似乎是将请求类型从 GET 更改为 POST 请求,在正文中发送搜索查询,而不是在 URI 中发送。然而,我在尝试使其正常工作时遇到了一些问题,因为我似乎无法从 POST 请求中正确填充 ODataQueryOptions 对象。我的 Web API 方法现在如下所示:

public IQueryable<ReportModel> Post([FromBody] ODataQueryOptions<Report> queryOptions)
{
      var query = DbContext.Query<Report>();

      return (queryOptions.ApplyTo(query) as IQueryable<Report>).WithTranslations().Project(MappingEngine).To<ReportModel>().WithTranslations();
}

正如您所看到的,我尝试从请求正文而不是从 URI 填充查询选项。到目前为止,我还无法从请求中获取要填充的 ODataQueryOptions 参数,并且该参数结果为“null”。如果我删除“[FromBody]”属性,查询选项对象将从请求 URI 中正确填充,但同样的 URI 长度问题仍然存在。

以下是我如何从浏览器调用该方法的示例(使用 jQuery):

$.ajax({
       url: "/API/Report",
       type: "POST",
       data: ko.toJSON({
           '$filter': 'Field1+eq+1%20or%20Field1+eq+5%20or%20Field1+eq+10%20or%20Field1+eq+15...'
       }),
       dataType: "json",
       processData: false,
       contentType: 'application/json; charset=utf-8',
});

首先,是否可以执行我在这里尝试执行的操作(在请求正文中发布 ODataQueryOptions)?如果是这样,我是否正确构建了 POST 请求?我还缺少什么吗?


您可以在帖子正文中传递查询选项的原始字符串值, 并在控制器的 post 方法中构造一个查询选项。

下面的代码仅用于过滤查询选项。 您可以以同样的方式添加其他查询选项。

public IQueryable<ReportModel> Post([FromBody] string filterRawValue)
{
    var context = new ODataQueryContext(Request.ODataProperties().Model, typeof(Report));
    var filterQueryOption = new FilterQueryOption(filterRawValue, context);
    var query = DbContext.Query<Report>();
    return (filterQueryOption.ApplyTo(query) as IQueryable<Report>).WithTranslations().Project(MappingEngine).To<ReportModel>().WithTranslations();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

可以从 Http 请求主体发布 ODataQueryOptions 吗? 的相关文章

随机推荐