OData的V4修改$过滤器上的服务器端 [英] OData V4 modify $filter on server side

查看:149
本文介绍了OData的V4修改$过滤器上的服务器端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想是能够修改滤波器控制器内,然后再返回基础上改变的过滤器的数据。

所以对我有,我可以用看FilterQueryOption服务器端的ODataQueryOptions参数。

假设过滤器是这样的$ =过滤器EQ ID -1,但在服务器端,如果我看到-1为ID这告诉我,用户要选择所有的记录。

我试图改变$过滤器= ID EQ -1到$过滤器= ID NE -1,这会给我所有通过设置Filter.RawValue但这是只读的。结果
我试图创建一个新的FilterQueryOption但这需要ODataQueryContext和我无法弄清楚如何创建一个ODataQueryOptionParser。

然后我试图设置过滤器= NULL,然后我们似乎在ApplyTo当我设置在控制器一个破发点工作,检查这立即窗口上,但一旦离开控制器上的GET方法,那么它恢复回什么是在URL中传递。

这篇文章做得非常类似<一会谈href=\"http://stackoverflow.com/questions/16440644/the-best-way-to-modify-a-webapi-odata-queryoptions-filter\">The修改的WebAPI的OData QueryOptions.Filter最好的办法的,但一旦离开控制器GET方法则恢复到URL查询过滤器。

与样品code UPDATE

  [EnableQuery]
[HTTPGET]
公众的IQueryable&LT;产品与GT;的GetProducts(ODataQueryOptions&LT;产品与GT; queryOptions)
{
    如果(queryOptions.Filter!= NULL)
    {
        VAR URL = queryOptions.Request.RequestUri.AbsoluteUri;
        字符串过滤器= queryOptions.Filter.RawValue;        URL = url.Replace($过滤器= ID%20eq%201,$过滤器= ID%20eq%202);
        VAR REQ =新的Htt prequestMessage(HttpMethod.Get,URL);        queryOptions =新ODataQueryOptions&LT;产品及GT;(queryOptions.Context,REQ);
    }    IQueryable的查询= queryOptions.ApplyTo(db.Products.AsQueryable());
    返回查询作为IQueryable的&LT;产品取代;
}

运行此code将不会返回任何产品,这是因为在URL中的原始查询想要的产品1和我换产品1的ID过滤器产品2.结果
现在,如果我运行SQL事件探查器,我可以看到它补上一句,从产品选择* WHERE ID = 1和ID = 2。

BUT 如果我通过更换$顶部做同样的事情,然后它工作正常。

  [EnableQuery]
[HTTPGET]
公众的IQueryable&LT;产品与GT;的GetProducts(ODataQueryOptions&LT;产品与GT; queryOptions)
{
    如果(queryOptions.Top!= NULL)
    {
        VAR URL = queryOptions.Request.RequestUri.AbsoluteUri;
        字符串过滤器= queryOptions.Top.RawValue;        网址= url.Replace($顶端= 2,$顶端= 1);
        VAR REQ =新的Htt prequestMessage(HttpMethod.Get,URL);        queryOptions =新ODataQueryOptions&LT;产品及GT;(queryOptions.Context,REQ);
    }    IQueryable的查询= queryOptions.ApplyTo(db.Products.AsQueryable());
    返回查询作为IQueryable的&LT;产品取代;
}

END结果结果
随着微软的帮助。这里是一个支持过滤器,计数,和寻呼的最终输出。

使用System.Net.Http;
使用System.Web.OData;
使用System.Web.OData.Extensions;
使用System.Web.OData.Query;///&LT;总结&gt;
///用于创建自定义过滤器,选择,分组,排序等...
///&LT; /总结&gt;
公共类CustomEnableQueryAttribute:EnableQueryAttribute
{
    公众覆盖IQueryable的ApplyQuery(IQueryable的可查询,ODataQueryOptions queryOptions)
    {
        IQueryable的结果=默认(IQueryable的);        //得到改变之前,原来的请求
        HTT prequestMessage originalRequest = queryOptions.Request;        //得到改变之前的原始网址
        字符串的URL = originalRequest.RequestUri.AbsoluteUri;        //重建URL,如果它包含了ID = 0选择所有记录特定的过滤器
        如果(queryOptions.Filter = NULL&放大器;!&安培; url.Contains($过滤器= ID%20eq%200))
        {
            //应用新的过滤器
            URL = url.Replace($过滤器= ID%20eq 200%,$过滤器= ID%20NE%200);            //建立过滤器的新请求
            HTT prequestMessage REQ =新HTT prequestMessage(HttpMethod.Get,URL);            //使用新的要求重新设置查询选项
            queryOptions =新ODataQueryOptions(queryOptions.Context,REQ);
        }        //设置一个最高过滤器如果未提供
        如果(queryOptions.Top == NULL)
        {
            //申请查询选项与新的过滤器顶部
            结果= queryOptions.ApplyTo(可查询,新ODataQuerySettings {每页= 100});
        }
        其他
        {
            //申请,这不是previously应用的任何未决的信息
            结果= queryOptions.ApplyTo(可查询);
        }        //添加NEXTLINK如果存在
        如果(queryOptions.Request.ODataProperties()。NEXTLINK!= NULL)
        {
            。originalRequest.ODataProperties()NEXTLINK = queryOptions.Request.ODataProperties()NEXTLINK。
        }
        //添加TOTALCOUNT如果存在
        如果(queryOptions.Request.ODataProperties()。TOTALCOUNT!= NULL)
        {
            originalRequest.ODataProperties()= TOTALCOUNT queryOptions.Request.ODataProperties()TOTALCOUNT。;
        }        //返回所有结果
        返回结果;
    }
}


解决方案

删除[EnableQuery]属性,你的情况应该工作,因为使用这个属性之后,的OData /的WebAPI将你的控制器返回数据后应用原来的查询选项,如果你已经在你的控制器使用方法,那么你不应该使用该属性。

但是,如果您的查询选项包含$选择,那些code不工作,因为结果的类型不是产品,我们使用的包装重新present的$结果选择,所以我建议你使用try这样的:

制作定制EnableQueryAttribute

 公共类MyEnableQueryAttribute:EnableQueryAttribute
{
    公众覆盖IQueryable的ApplyQuery(IQueryable的可查询,ODataQueryOptions queryOptions)
    {
        如果(queryOptions.Filter!= NULL)
        {
            queryOptions.ApplyTo(可查询);
            VAR URL = queryOptions.Request.RequestUri.AbsoluteUri;            URL = url.Replace($过滤器= ID%20eq%201,$过滤器= ID%20eq%202);
            VAR REQ =新的Htt prequestMessage(HttpMethod.Get,URL);            queryOptions =新ODataQueryOptions(queryOptions.Context,REQ);
        }        返回queryOptions.ApplyTo(可查询);
    }
}

在您的控制器方法使用该属性

  [MyEnableQueryAttribute]
公共IHttpActionResult获得()
{
    返回OK(_产品展示);
}

希望这能解决你的问题,谢谢!

风扇。

I would like to be able to modify the filter inside the controller and then return the data based on the altered filter.

So for I have an ODataQueryOptions parameter on the server side that I can use to look at the FilterQueryOption.

Let's assume the filter is something like this "$filter=ID eq -1" but on the server side if I see "-1" for an ID this tells me that the user wants to select all records.

I tried to change the "$filter=ID eq -1" to "$filter=ID ne -1" which would give me all by setting the Filter.RawValue but this is read only.
I tried to create a new FilterQueryOption but this requires a ODataQueryContext and a ODataQueryOptionParser which I can't figure out how to create.

I then tried to set the Filter = Null and then us the ApplyTo which seems to work when I set a break point in the controller and check this on the immediate window but once it leaves the GET method on the controller then it "reverts" back to what was passed in the URL.

This article talks about doing something very similar "The best way to modify a WebAPI OData QueryOptions.Filter" but once it leaves the controller GET method then it reverts back to the URL query filter.

UPDATE WITH SAMPLE CODE

[EnableQuery]
[HttpGet]
public IQueryable<Product> GetProducts(ODataQueryOptions<Product> queryOptions)
{
    if (queryOptions.Filter != null)
    {
        var url = queryOptions.Request.RequestUri.AbsoluteUri;
        string filter = queryOptions.Filter.RawValue;

        url = url.Replace("$filter=ID%20eq%201", "$filter=ID%20eq%202");
        var req = new HttpRequestMessage(HttpMethod.Get, url);

        queryOptions = new ODataQueryOptions<Product>(queryOptions.Context, req);
    }

    IQueryable query = queryOptions.ApplyTo(db.Products.AsQueryable());
    return query as IQueryable<Product>;
}

Running this code will not return any product this is because the original query in the URL wanted product 1 and I swapped the ID filter of product 1 with product 2.
Now if I run SQL Profiler, I can see that it added something like "Select * from Product WHERE ID = 1 AND ID = 2".

BUT if I try the same thing by replacing the $top then it works fine.

[EnableQuery]
[HttpGet]
public IQueryable<Product> GetProducts(ODataQueryOptions<Product> queryOptions)
{
    if (queryOptions.Top != null)
    {
        var url = queryOptions.Request.RequestUri.AbsoluteUri;
        string filter = queryOptions.Top.RawValue;

        url = url.Replace("$top=2", "$top=1");
        var req = new HttpRequestMessage(HttpMethod.Get, url);

        queryOptions = new ODataQueryOptions<Product>(queryOptions.Context, req);
    }

    IQueryable query = queryOptions.ApplyTo(db.Products.AsQueryable());
    return query as IQueryable<Product>;
}

END RESULT
With Microsoft's help. Here is the final output that supports filter, count, and paging.

using System.Net.Http;
using System.Web.OData;
using System.Web.OData.Extensions;
using System.Web.OData.Query;

/// <summary>
/// Used to create custom filters, selects, groupings, ordering, etc...
/// </summary>
public class CustomEnableQueryAttribute : EnableQueryAttribute
{
    public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
    {
        IQueryable result = default(IQueryable);

        // get the original request before the alterations
        HttpRequestMessage originalRequest = queryOptions.Request;

        // get the original URL before the alterations
        string url = originalRequest.RequestUri.AbsoluteUri;

        // rebuild the URL if it contains a specific filter for "ID = 0" to select all records
        if (queryOptions.Filter != null && url.Contains("$filter=ID%20eq%200")) 
        {
            // apply the new filter
            url = url.Replace("$filter=ID%20eq%200", "$filter=ID%20ne%200");

            // build a new request for the filter
            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, url);

            // reset the query options with the new request
            queryOptions = new ODataQueryOptions(queryOptions.Context, req);
        }

        // set a top filter if one was not supplied
        if (queryOptions.Top == null) 
        {
            // apply the query options with the new top filter
            result = queryOptions.ApplyTo(queryable, new ODataQuerySettings { PageSize = 100 });
        } 
        else 
        {
            // apply any pending information that was not previously applied
            result = queryOptions.ApplyTo(queryable);
        }

        // add the NextLink if one exists
        if (queryOptions.Request.ODataProperties().NextLink != null) 
        {
            originalRequest.ODataProperties().NextLink = queryOptions.Request.ODataProperties().NextLink;
        }
        // add the TotalCount if one exists
        if (queryOptions.Request.ODataProperties().TotalCount != null) 
        {
            originalRequest.ODataProperties().TotalCount = queryOptions.Request.ODataProperties().TotalCount;
        }

        // return all results
        return result;
    }
}

解决方案

Remove [EnableQuery] attribute, your scenario should work, because after using this attribute, OData/WebApi will apply your original query option after you return data in controller, if you already apply in your controller method, then you shouldn't use that attribute.

But if your query option contains $select, those code are not working because the result's type is not Product, we use a wrapper to represent the result of $select, so I suggest you use try this:

Make a customized EnableQueryAttribute

public class MyEnableQueryAttribute : EnableQueryAttribute
{
    public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
    {
        if (queryOptions.Filter != null)
        {
            queryOptions.ApplyTo(queryable);
            var url = queryOptions.Request.RequestUri.AbsoluteUri;

            url = url.Replace("$filter=Id%20eq%201", "$filter=Id%20eq%202");
            var req = new HttpRequestMessage(HttpMethod.Get, url);

            queryOptions = new ODataQueryOptions(queryOptions.Context, req);
        }

        return queryOptions.ApplyTo(queryable);
    }
}

Use this attribute in your controller method

[MyEnableQueryAttribute]
public IHttpActionResult Get()
{
    return Ok(_products);
}

Hope this can solve your problem, thanks!

Fan.

这篇关于OData的V4修改$过滤器上的服务器端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆