如何修改OData查询以添加访问过滤器?

我有一个C#OData端点,我需要评估使用OData查询提交的过滤器,以确定是否需要添加其他过滤器来限制返回给用户的结果.

我的示例模型很简单:

学生 – >图书目录 – >图书
(所有实体都分配了CampusId属性.)

当属于Campus#5的用户执行以下查询时:
“学生$选择= ID,名字,CampusId”
它应该转变为:
“学生$select = Id,姓名,CampusId& $filter = CampusId eq 5”

我只需将过滤器添加为字符串即可通过简单查询完成此操作.

我真正想做的是:
1)确定正在选择和扩展的实体
2)确定这些实体是否具有CampusId属性
3)将必要的过滤器值添加到Uri中,以便将每个选定和/或扩展实体的查询过滤到该校园

我试图使用Microsoft.OData.Core.UriParser.ODataUriParser来解析过滤器值,然后创建一个新的Uri.

例如:

var parser = new Microsoft.OData.Core.UriParser.ODataUriParser(edmModel, new Uri(serviceRootPath), originalUri);
var filter = parser.ParseFilter();

使用上面的代码片段,您将获得“filter”变量,以提供一种类型的Microsoft.OData.Core.UriParser.Semantic.FilterClause,可用于检查OData Query Uri中的当前过滤器值.

有谁知道如何编辑FilterClause中的值,以便能够向Uri添加新的过滤器值?

我没有找到很多关于如何编辑FilterClause的示例,以便使用新的过滤器值生成更新的Uri.

最佳答案 我通过编写一个算法为我的isse找到了解决方案,该算法根据模型的属性为请求ODataUri添加了额外的过滤.它会检查根级实体的任何属性以及任何已扩展实体的属性,以确定要添加到OData查询的其他过滤器表达式.

OData v4支持在$expand子句中进行过滤,但扩展实体中的filterOption是只读的,因此您无法修改扩展实体的过滤器表达式.您只能检查扩展实体的filterOption内容.

我的解决方案是检查所有实体(根和扩展)的属性,然后在请求ODataUri的根过滤器中添加我需要的任何其他$filter选项.

以下是OData请求Url的示例:

/RootEntity?$expand=OtherEntity($expand=SomeOtherEntity)

我更新后,这是相同的OData请求Url:

/RootEntity?$filter=OtherEntity/SomeOtherEntity/Id eq 3&$expand=OtherEntity($expand=SomeOtherEntity)

我用来完成这个步骤:

>使用ODataUriParser将传入的Url解析为Uri对象

见下文:

var parser = new ODataUriParser(model, new Uri(serviceRootPath), requestUri);   
var odataUri = parser.ParseUri();

>创建一个将从根遍历到所有扩展实体的方法,并通过ref传递ODataUri(以便在检查每个实体时根据需要更新它)

第一种方法将检查根实体,并根据根实体的属性添加任何其他过滤器.

AddCustomFilters(ref ODataUri odataUri);

AddCustomFilters方法将遍历展开的实体并调用AddCustomFiltersToExpandedEntity,它将继续遍历所有展开的实体以添加任何必要的过滤器.

foreach (var item in odatauri.SelectAndExpand.SelectedItems)
{
    AddCustomFiltersToExpandedEntity(ref ODataUri odataUri, ExpandedNavigationSelectItem expandedNavigationSelectItem, string parentNavigationNameProperty)
}

AddCustomFiltersToExpandedEntity方法应该调用自身,因为它循环遍历每个级别的展开实体.

>在检查每个实体时更新根过滤器

使用其他筛选器要求创建新的筛选器子句,并覆盖根级别的现有筛选器子句. ODataUri根级别的$filter有一个setter,因此可以覆盖它.

odataUri.Filter = new FilterClause(newFilterExpression, newFilterRange);

注意:我使用BinaryOperatorKind.And创建了一个新的过滤器子句,以便将任何其他过滤器表达式简单地附加到ODataUri中已有的任何现有过滤器表达式

var combinedFilterExpression = new BinaryOperatorNode(BinaryOperatorKind.And, odataUri.Filter.Expression, newFilterExpression);
odataUri.Filter = new FilterClause(combinedFilterExpression, newFilterRange);

>使用ODataUriBuilder根据更新的Uri创建新的Url

见下文:

var updatedODataUri = new Microsoft.OData.Core.UriBuilder.ODataUriBuilder(ODataUrlConventions.Default, odataUri).BuildUri();

>用更新的Uri替换请求Uri.

这允许OData控制器使用更新的OData Url完成处理请求,其中包括您刚添加到根级别文件管理器的其他过滤器选项.

ActionContext.Request.RequestUri = updatedODataUri;

这使我能够添加我需要的任何过滤选项,并且100%确定我没有错误地更改OData Url结构.

我希望这在面对同样的问题时可以帮助别人.

点赞