我试图让OData端点启动并正常工作,我发现这个错误,即使谷歌也没什么可说的。
我已经创建了一个Entity Framework EDMX上下文(数据库优先),让设计师从中生成2个模型。
一切正常,但$filter
查询失败。
我可以做得很好:
http://localhost:27164/Projects(6587660)
使用主ID为6587660检索项目。
但是任何$filter
请求都是这样的:
http://localhost:27164/Projects?$filter=ProjectID eq 6587660
将因以下错误而失败:
URI中指定的查询无效。物业' ProjectID'不能在$ filter查询选项中使用。
我也尝试过查询其他属性,字符串属性。同样的错误。
我已经检查过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()
);
}
这里是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与数据库优先使用,所以我不确定导致这种情况的原因。
我在.NET 4.5.2上使用Nuget的最新运行时。
答案 0 :(得分:111)
来自the docs 13.1 Model Bound Attributes:
现在,WebAPI OData的默认设置是:客户端无法应用 $ count,$ orderby,$ select,$ top,$ expand,$ filter查询,查询 像localhost \ odata \ Customers?$ orderby =名称将失败为 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月编辑:
每个实体的流畅API似乎存在错误。尽管使用流畅的API设置了实体集,但对$expand
实体集的调用会间歇性地返回400 Bad Request并在原始问题中出现错误。我不知道这个错误是仅存在于$expand
还是存在于其他查询参数中。我也不知道是我的代码是导致问题还是MS错误,因此是其他人遇到的问题。我将很快对此进行调查并更新此答案。现在我正在使用单线捕捉全部;效果很好。
进一步修改:
我刚刚重读了the docs的一些内容(尝试让这个更新尽可能理解),它们似乎意味着我现在设置的方式(使用Global Config one-line-catch) -all加上流畅的API),每个实体的流畅API仍将受到尊重,因为:
“查询设置可以放在很多地方,具体如下 从最低到最高的优先级:系统默认值(不能查询 默认),全局配置,模型绑定属性,Fluent API。“
因此,也许这就是你要做的事情:添加one-line-catch-all然后使用模型绑定属性,流畅API或两者进行微调。我需要对此进行测试并尽快报告...
答案 1 :(得分:0)
要回答@NickG等人提出的问题: 在.Net Core中,您可以执行类似的操作:
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
var products = builder.EntitySet<Product>("Products");
products.EntityType.Count().Filter().OrderBy().Expand().Select();
return builder.GetEdmModel();
}