OData 错误:URI 中指定的查询无效。该属性不能在查询选项中使用
Posted
技术标签:
【中文标题】OData 错误:URI 中指定的查询无效。该属性不能在查询选项中使用【英文标题】:OData Error: The query specified in the URI is not valid. The property cannot be used in the query option 【发布时间】:2017-01-23 17:20:20 【问题描述】:我正在尝试启动 OData 端点并使其正常工作,但我遇到了这个错误,即使是 Google 也无话可说。
我创建了一个实体框架 EDMX 上下文(首先是数据库),让设计人员从中生成 2 个模型。
一切正常,除了$filter
查询失败。
我可以做到这一点:
http://localhost:27164/Projects(6587660)
检索主 ID 为 6587660 的项目。
但是任何$filter
的请求都是这样的:
http://localhost:27164/Projects?$filter=ProjectID eq 6587660
将失败并出现以下错误:
URI 中指定的查询无效。 $filter 查询选项中不能使用属性“ProjectID”。
我也尝试过查询其他属性,字符串属性也是如此。同样的错误。
我检查了 EF 生成的模型在属性上没有任何属性,它们没有。
这是我在 WebApiConfig.cs 模块中的注册方法:
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
public static void Register(HttpConfiguration config)
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<DB.Project>("Projects");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel()
);
这是 Projects 控制器(GetProjects 是执行 $filter 查询时调用的方法):
public class ProjectsController : ODataController
private AppContext db = new AppContext();
//I've tried decorating with that: [EnableQuery(AllowedQueryOptions = System.Web.OData.Query.AllowedQueryOptions.All, AllowedArithmeticOperators = System.Web.OData.Query.AllowedArithmeticOperators.All)] and no go
[EnableQuery]
public IQueryable<Project> GetProjects()
return db.Projects;
// GET: odata/Projects(5)
[EnableQuery]
public SingleResult<Project> GetProject([FromODataUri] int key)
return SingleResult.Create(db.Projects.Where(project => project.ProjectID == key));
/*
// PUT: odata/Projects(5)
public IHttpActionResult Put([FromODataUri] int key, Delta<Project> patch)
Validate(patch.GetEntity());
if (!ModelState.IsValid)
return BadRequest(ModelState);
Project project = db.Projects.Find(key);
if (project == null)
return NotFound();
patch.Put(project);
try
db.SaveChanges();
catch (DbUpdateConcurrencyException)
if (!ProjectExists(key))
return NotFound();
else
throw;
return Updated(project);
// POST: odata/Projects
public IHttpActionResult Post(Project project)
if (!ModelState.IsValid)
return BadRequest(ModelState);
db.Projects.Add(project);
db.SaveChanges();
return Created(project);
// PATCH: odata/Projects(5)
[AcceptVerbs("PATCH", "MERGE")]
public IHttpActionResult Patch([FromODataUri] int key, Delta<Project> patch)
Validate(patch.GetEntity());
if (!ModelState.IsValid)
return BadRequest(ModelState);
Project project = db.Projects.Find(key);
if (project == null)
return NotFound();
patch.Patch(project);
try
db.SaveChanges();
catch (DbUpdateConcurrencyException)
if (!ProjectExists(key))
return NotFound();
else
throw;
return Updated(project);
// DELETE: odata/Projects(5)
public IHttpActionResult Delete([FromODataUri] int key)
Project project = db.Projects.Find(key);
if (project == null)
return NotFound();
db.Projects.Remove(project);
db.SaveChanges();
return StatusCode(HttpStatusCode.NoContent);
*/
protected override void Dispose(bool disposing)
if (disposing)
db.Dispose();
base.Dispose(disposing);
private bool ProjectExists(int key)
return db.Projects.Count(e => e.ProjectID == key) > 0;
这是我第一次将 OData 与 Database First 结合使用,所以我不确定是什么原因造成的。
我在 .NET 4.5.2 上使用来自 Nuget 的最新运行时。
【问题讨论】:
会不会是物业的情况?你试过$filter=projectId eq 6587660
或$filter=projectID eq 6587660
吗?
@Igor 我试过了。任何其他大小写都会返回一个错误,说明该属性不存在,所以我的大小写是正确的。
您是否尝试过 $filter
使用模型上的另一个属性(如字符串属性)?
您是否启用(或未设置)任何these options,它会阻止您使用$filter
?目前这是很多猜测和问题,您应该提供一些代码,例如您正在使用的配置和 odata 控制器,以提供更多信息。
我遇到了完全相同的问题。我实际上不能使用任何查询语法参数,$count、$filter、$select 等。它们都失败了。
【参考方案1】:
来自the docs 13.1 Model Bound Attributes:
现在 WebAPI OData 的默认设置是:client can't apply
$count
,$orderby
,$select
,$top
,$expand
,$filter
在查询中,像localhost\odata\Customers?$orderby=Name
这样的查询将失败为 BadRequest,因为默认情况下所有属性都不能排序,所以这个 是 6.0.0 中的重大变化
所以,我们现在需要启用 OData 模型绑定属性,您可以使用以下块中的中间行全局执行(另外两个是您的代码):
ODataModelBuilder builder = new ODataConventionModelBuilder();
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null); //new line
builder.EntitySet<DB.Project>("Projects");
但这是一个包罗万象的工作,围绕这一变化带来的更好的安全性/性能。
因此,您可以并且也许应该使用每个实体的流畅 API 调用来启用 OData 模型绑定属性,如下所示:
builder.EntitySet<DB.Project>("Projects"); //your line of code
builder.EntityType<DB.Project>().Filter("ProjectID");
这个答案应该可以解决您发布的问题,但我希望您需要查看 those docs 以使您能够为项目的其余部分制定一个全面的解决方案(当然,除非您只需部署一条线就可以了!)。
正如“模型绑定属性”的名称所暗示的那样,您还可以通过模型上的属性来实现您所需要的,这也包含在the docs 中(实际上也是主要关注点)。
2017 年 2 月编辑:
per-entity fluent API 中似乎存在错误。尽管实体集是使用流畅的 API 设置的,但对 $expand
实体集的调用会间歇性地返回 400 错误请求,并显示原始问题中的错误。我不知道这个错误是否只存在于$expand
或其他查询参数中。我也不知道是我的代码导致了问题还是 MS 错误,因此其他人也遇到了问题。我将很快对此进行进一步调查并更新此答案。现在我正在使用单行捕获所有;效果很好。
进一步编辑:
我刚刚重读了一些the docs(试图让这个更新尽可能容易理解),它们似乎暗示我现在的设置方式(使用全局配置单线捕获所有加上fluent API),仍然会尊重per-entity fluent API,因为:
"查询设置可以放在很多地方,如下 优先级从低到高:系统默认(不可查询 默认)、全局配置、模型绑定属性、Fluent API。”
因此,也许这就是您必须做的:添加一条线-全部捕获,然后使用模型绑定属性、流式 API 或两者进行微调。我需要对此进行测试,并会尽快报告...
【讨论】:
突破性变化好吧。这有点打破了我对使用 MS 的 OData 实现的兴趣。还是非常感谢。 @FrancisDucharme 不要对变化过于失望;这是一个很好的安全/性能增强功能,如果您不需要细粒度的控制,则可以解决所有问题。乐意效劳。 :-) @lukkea 我确信 SO 问题会有所帮助,但如果 OData 团队中的任何人在倾听,那么更好的错误消息也会大大有助于将我指向正确的方向。 如何获得“config”对象?这是哪里来的?我正在使用 .NET 核心,但似乎看不到等效功能。 @NickG 看看这个问题 - 这就是我从中获取配置对象的地方。【参考方案2】:回答@NickG 等人提出的问题: 在 .Net Core 中,您可以执行类似的操作:
private static IEdmModel GetEdmModel()
var builder = new ODataConventionModelBuilder();
var products = builder.EntitySet<Product>("Products");
products.EntityType.Count().Filter().OrderBy().Expand().Select();
return builder.GetEdmModel();
【讨论】:
以上是关于OData 错误:URI 中指定的查询无效。该属性不能在查询选项中使用的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 C# 为 OData 查询中指定的每个过滤器获取一组键/值对?