在WebApi的ApiController上启用OData v4查询

4

我正在努力将OData v4查询支持添加到一个继承自ApiController而不是ODataController的控制器方法中。虽然我在解决方案中有一个工作的OData模型,但有一些端点并不真正属于该模型,但查询的强大功能会很有用。

我看到一些文章建议我只需返回IQueryable并使用EnableQuery即可。

这是我的示例代码:

public class TestController : ApiController
{
    [HttpGet]    
    [EnableQuery]
    public IQueryable<TestObject> Events()
    {
        var result = new[] { new TestObject { Id = "1" } }.AsQueryable();
        return result;
    }
}

public class TestObject
{
    public string Id { get; set; }
}

当我调用/Test/Events时,只返回了一个406 Not Acceptable,我在处理OData时经常遇到这种情况,通常意味着我返回了OData框架不喜欢的内容。我以前从未能够从框架中获取更多信息(我认为这是一个重大缺陷),只能通过试验和错误来解决问题。
有人成功配置过吗?如果是,请分享一下经验?
或者,有什么关于调试406响应的建议?
编辑:
好吧,事实证明罪魁祸首是启动中注册自定义ODataMediaTypeFormatter的一些代码,在此过程中清除了所有其他格式化程序。
删除有问题的代码后,它就工作了。
真的希望WebApi在输出406错误时能够记录产生错误的原因。

你是如何声明路由的? - nlips
我并没有使用EnableQuery,我只是使用了控制器/操作的规则。在删除EnableQuery时它运行良好。 - Mant101
将动作名称Events()更改为Get()是否有效? - eoghank
没有,使用EnableQuery会出现我老朋友406的错误,如果重命名为GET /Test,则可以正常工作。 - Mant101
1个回答

0

您可以手动应用“query”魔法,而无需[EnableQuery]。

  1. 创建一个ODataQueryContext,传入您的模型(您需要将其保存在全局并使其可用),以及您正在查询的实体类型。
  2. 使用Get和当前url(Request.RequestUri.AbsoluteUri)创建一个HttpRequestMessage。
  3. 创建一个新的ODataQueryOptions<yourEntity>,传入您创建的上下文和请求消息。
  4. 使用entity.AsQueryable()调用该对象的ApplyTo,将结果强制转换为IQueryable<yourEntity>。

进一步操作所需并返回。请记住,返回类型不需要是IQueryable<yourEntity>,甚至不基于“yourEntity”。

这里有一个类似的实现,它为ODataController方法执行此操作(因为基本的ODataQueryOptions是免费的):

        public IEnumerable<Aggregate> GetOrders(ODataQueryOptions<ReportingOrder> opts, [FromUri(Name="$groupby")]string groupby, [FromUri(Name="$aggregates")]string aggregates = null)
        {
            var url = opts.Request.RequestUri.AbsoluteUri;


            int? top = null;

            if (opts.Top != null)
            {
                top = int.Parse(opts.Top.RawValue);

                var topStr = string.Format("$top={0}", top.Value);
                url = url.Replace(topStr, "");
                var req = new HttpRequestMessage(HttpMethod.Get, url);

                opts = new ODataQueryOptions<ReportingOrder>(opts.Context, req);

            }

            var query = opts.ApplyTo(db.ReportingOrders.AsQueryable()) as IQueryable<ReportingOrder>;

            var results = query.GroupBy(groupby, aggregates, top);

            return results;
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接