我正在尝试启动并运行 OData 端点,但我遇到了这个错误,即使是 Google 也没有太多可说的。
我创建了一个 Entity Framework EDMX 上下文(首先是数据库),让设计人员从中生成 2 个模型。
一切正常,除了 $filter
查询失败。
我可以做到这一点:
http://localhost:27164/Projects(6587660)
它检索主 ID 为 6587660 的项目。
但是任何 $filter
请求都是这样的:
http://localhost:27164/Projects?$filter=ProjectID eq 6587660
将失败并出现以下错误:
The query specified in the URI is not valid. The property 'ProjectID' cannot be used in the $filter query option.
我也试过查询其他属性,字符串属性。同样的错误。
我检查过 EF 生成的模型在属性上没有任何属性,它们没有。
这是我在 WebApiConfig.cs 模块中的 Register 方法:
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()
);
}
这是项目 Controller (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 与数据库优先一起使用,所以我不确定是什么原因造成的。
我在 .NET 4.5.2 上使用 Nuget 的最新运行时。
最佳答案
来自 the docs 13.1 Model Bound Attributes :
Now the default setting for WebAPI OData is : client can’t apply
$count
,$orderby
,$select
,$top
,$expand
,$filter
in the query, query likelocalhost\odata\Customers?$orderby=Name
will failed as BadRequest, because all properties are not sort-able by default, this is a breaking change in 6.0.0
因此,我们现在需要启用 OData 模型绑定(bind)属性,您可以在以下 block 的中间行全局执行此操作(其他两个是您的代码):
ODataModelBuilder builder = new ODataConventionModelBuilder();
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null); //new line
builder.EntitySet<DB.Project>("Projects");
但这是一种包罗万象的方法,可以解决此更改带来的更好的安全性/性能问题。
因此,您可以并且也许应该像这样对每个实体使用流畅的 API 调用来启用 OData 模型绑定(bind)属性:
builder.EntitySet<DB.Project>("Projects"); //your line of code
builder.EntityType<DB.Project>().Filter("ProjectID");
这个答案应该可以解决您发布的问题,但我希望您需要看一下 those docs使您能够为项目的其余部分制定一个全面的解决方案(当然,除非您只是部署一条线包罗万象!)。
正如名称“模型绑定(bind)属性”所暗示的那样,您还可以通过模型上的属性来实现您需要的功能,这在(实际上是主要关注点)the docs 中有所介绍。也是。
编辑 2017 年 2 月:
每个实体的 Fluent API 中似乎存在错误。对 $expand
实体集的调用会间歇性地返回一个 400 Bad Request 以及原始问题中的错误,尽管实体集是使用流畅的 API 设置的。我不知道这个错误是否只存在于 $expand
或其他查询参数中。我也不知道是我的代码导致了问题还是 MS 错误,因此其他人遇到了问题。我将很快对此进行进一步调查并更新此答案。现在我正在使用单线包罗万象;效果很好。
进一步编辑:
我刚刚重读了一些 the docs (尝试让这个更新尽可能易于理解)并且它们似乎暗示我现在设置事物的方式(使用 Global Config one-line-catch-all plus fluent API),每个实体的 fluent API 将仍然受到尊重,因为:
"Query settings can be placed in many places, with the following precedence from lowest to highest: System Default(not query-able by default), Global Configuration, Model Bound Attribute, Fluent API."
因此,也许这就是您必须做的:添加一行包罗万象的内容,然后使用模型绑定(bind)属性、流畅的 API 或两者进行微调。我需要对此进行测试,并会尽快报告...
关于c# - OData 错误 : The query specified in the URI is not valid. 该属性不能在查询选项中使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39515218/