gor*_*oth 15 odata asp.net-web-api entity-framework-6 asp.net-web-api2
我希望能够修改控制器内的过滤器,然后根据更改的过滤器返回数据.
因此,我在服务器端有一个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中传递的内容.
本文讨论了做一些非常相似的" 修改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>;
}
Run Code Online (Sandbox Code Playgroud)
运行此代码不会返回任何产品,因为URL中的原始查询需要产品1,我将产品1的ID过滤器与产品2交换.
现在,如果我运行SQL事件探查器,我可以看到它添加了类似"选择"的内容*来自产品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>;
}
Run Code Online (Sandbox Code Playgroud)
最终结果
在微软的帮助下.这是支持过滤,计数和分页的最终输出.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
删除[EnableQuery]属性,您的方案应该可以工作,因为在使用此属性后,OData/WebApi将在您在控制器中返回数据后应用原始查询选项,如果您已经在控制器方法中应用,那么您不应该使用该属性.
但是如果你的查询选项包含$ select,那些代码不起作用,因为结果的类型不是Product,我们使用包装器来表示$ select的结果,所以我建议你使用试试这个:
制作自定义的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);
}
}
Run Code Online (Sandbox Code Playgroud)
在控制器方法中使用此属性
[MyEnableQueryAttribute]
public IHttpActionResult Get()
{
return Ok(_products);
}
Run Code Online (Sandbox Code Playgroud)
希望这可以解决您的问题,谢谢!
风扇.
响应@Chris Schaller,我发布了自己的解决方案,如下所示:
public class CustomEnableQueryAttribute : EnableQueryAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var url = actionContext.Request.RequestUri.OriginalString;
//change something in original url,
//for example change all A charaters to B charaters,
//consider decoding url using WebUtility.UrlDecode() if necessary
var newUrl = ModifyUrl(url);
actionContext.Request.RequestUri = new Uri(newUrl);
base.OnActionExecuting(actionContext);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11937 次 |
最近记录: |