【问题标题】:The best way to modify a WebAPI OData QueryOptions.Filter修改 Web API OData Query Options.Filter 的最佳方式
【发布时间】:2013-05-02 16:21:32
【问题描述】:

我正在使用http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations 的 OData 示例项目。在 Get 中,我希望能够更改 EntitySetController 的 QueryOptions 中的过滤器:

public class ProductsController : EntitySetController<Product, int>
{
    ProductsContext _context = new ProductsContext();

    [Queryable(AllowedQueryOptions=AllowedQueryOptions.All)]
    public override IQueryable<Product> Get()
    {
        var products = QueryOptions.ApplyTo(_context.Products).Cast<Product>();
        return products.AsQueryable();
    }

我希望能够找到特别提到的属性。我可以通过解析this.QueryOptions.Filter.RawValue 的属性名称来做到这一点,但我无法更新RawValue,因为它是只读的。但是,我可以从修改后的RawValue 创建另一个FilterQueryOption 实例,但我不能将它分配给this.QueryOptions.Filter,因为这也是只读的。

我想我可以调用新过滤器的ApplyTo 传递它_context.Products,但是我需要单独调用QueryOptions 的其他属性的ApplyTo,例如SkipOrderBy。还有比这更好的解决方案吗?

更新

我尝试了以下方法:

    public override IQueryable<Product> Get()
    {
        IQueryable<Product> encryptedProducts = _context.Products;

        var filter = QueryOptions.Filter;
        if (filter != null && filter.RawValue.Contains("Name"))
        {
            var settings = new ODataQuerySettings();
            var originalFilter = filter.RawValue;
            var newFilter = ParseAndEncyptValue(originalFilter);
            filter = new FilterQueryOption(newFilter, QueryOptions.Context);
            encryptedProducts = filter.ApplyTo(encryptedProducts, settings).Cast<Product>();

            if (QueryOptions.OrderBy != null)
            {
                QueryOptions.OrderBy.ApplyTo<Product>(encryptedProducts);
            }
        }
        else
        {
            encryptedProducts = QueryOptions.ApplyTo(encryptedProducts).Cast<Product>();
        }

        var unencryptedProducts = encryptedProducts.Decrypt().ToList();

        return unencryptedProducts.AsQueryable();
    }

而且它似乎正在发挥作用。如果我设置断点,我可以在unencryptedProducts 列表中看到我的产品,但是当方法返回时,我没有得到任何项目。我尝试重新打开[Queryable(AllowedQueryOptions=AllowedQueryOptions.All)],但没有效果。任何想法为什么我没有收到物品?

更新 2

我发现我的查询被应用了两次,即使我没有使用Queryable 属性。这意味着即使我有要返回的项目,列表也被使用未加密的值查询,因此没有返回任何值。

我尝试改用ODataController

public class ODriversController : ODataController
{

    //[Authorize()]
    //[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IQueryable<Products> Get(ODataQueryOptions options)
    {

这成功了!这是否表明EntitySetController 中存在错误?

【问题讨论】:

  • 您是否试图限制客户端可以过滤的属性?
  • 不是您问题的答案,但是,我注意到您的代码中有问题。您可以使用 ODataQueryOptions 或 QueryableAttribute。 ODataQueryOptions 用于手动控制查询。 QueryableAttribute 用于自动应用查询。您的代码两者都有,这意味着查询将由 ODataQueryOptions.ApplyTo 应用两次,由 QueryableAttribute 应用一次。
  • 你能进一步解释你的场景吗?您是否尝试转换传入的 $filter 查询然后执行它?
  • 我想将过滤器中的值更改为加密值,以便过滤器对数据库中的加密值起作用。并非所有列都被加密,所以我需要在过滤器字符串中找到相关的列并只修改它们的值。感谢您的帮助和建议,这就像在火车上使用手机一样简短
  • @RaghuRamNadiminti 是的,我想更改过滤器中的值,然后执行它。非常感谢关于 QueryableAttribute 的提示。

标签: asp.net-web-api odata


【解决方案1】:

您可能需要重新生成 ODataQueryOptions 来解决您的问题。假设你想修改添加 $orderby,你可以这样做:

string url = HttpContext.Current.Request.Url.AbsoluteUri;
url += "&$orderby=name";
var request = new HttpRequestMessage(HttpMethod.Get, url);
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Product>("Product");
var options = new ODataQueryOptions<Product>(new ODataQueryContext(modelBuilder.GetEdmModel(), typeof(Product)), request);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多