【发布时间】:2016-02-13 03:21:53
【问题描述】:
我希望能够修改控制器内部的过滤器,然后根据更改后的过滤器返回数据。
所以我在服务器端有一个 ODataQueryOptions 参数,我可以用它来查看 FilterQueryOption。
假设过滤器类似于“$filter=ID eq -1”,但在服务器端,如果我看到 ID 为“-1”,这告诉我用户想要选择所有记录。
我尝试将“$filter=ID eq -1”更改为“$filter=ID ne -1”,这将通过设置 Filter.RawValue 为我提供所有信息,但这是只读的。
我尝试创建一个新的 FilterQueryOption,但这需要一个 ODataQueryContext 和一个 ODataQueryOptionParser,我不知道如何创建。
然后我尝试设置 Filter = Null,然后设置 ApplyTo,当我在控制器中设置断点并在即时窗口上检查它时,它似乎可以工作,但是一旦它离开控制器上的 GET 方法,然后它“恢复”返回到 URL 中传递的内容。
这篇文章讨论了做一些非常类似“The best way to modify a WebAPI OData QueryOptions.Filter”的事情,但是一旦离开控制器的 GET 方法,它就会恢复到 URL 查询过滤器。
使用示例代码更新
[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>;
}
运行此代码不会返回任何产品,这是因为 URL 中的原始查询想要产品 1,而我将产品 1 的 ID 过滤器换成了产品 2。
现在,如果我运行 SQL Profiler,我可以看到它添加了类似“Select * from Product WHERE ID = 1 AND ID = 2”的内容。
但是如果我通过替换 $top 来尝试同样的事情,那么它可以正常工作。
[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>;
}
结束结果
在微软的帮助下。这是支持过滤、计数和分页的最终输出。
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;
}
}
【问题讨论】:
标签: asp.net-web-api entity-framework-6 odata asp.net-web-api2