OData V4 在伺服器端修改 $filter
我希望能夠修改控制器內部的過濾器,然後根據更改的過濾器返回數據。
因此,對於我在伺服器端有一個 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>; }執行此程式碼將不會返回任何產品,這是因為 URL 中的原始查詢需要產品 1,我將產品 1 的 ID 過濾器與產品 2 交換。
現在,如果我執行 SQL Profiler,我可以看到它添加了類似“選擇* 來自產品 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>; }結束結果
在 Microsoft 的幫助下。這是支持過濾、計數和分頁的最終輸出。
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; } }
刪除 [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); } }在你的控制器方法中使用這個屬性
[MyEnableQueryAttribute] public IHttpActionResult Get() { return Ok(_products); }希望這能解決您的問題,謝謝!
Fan.