c# - OData 错误 : The query specified in the URI is not valid. 该属性不能在查询选项中使用

标签 c# .net entity-framework asp.net-web-api odata

我正在尝试启动并运行 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 like localhost\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/

相关文章:

c# - 声明整数为空

c# - 有人可以解释这个懒惰的评估代码吗?

c# - 事件参数中 IEnumerable 的最佳实践

c# - WCF中获取回调 channel 的IP地址

c# - 在 C# 中保存相同类型的有序值对的最佳类型是什么?

visual-studio-2010 - 具有继承、条件和外键的 Entity Framework

c# - 如何根据条件将数据绑定(bind)到 DTO 属性?

c# - 断言中的逻辑运算符是否可以接受?

c# - BackgroundWorker 返回一个值?

c# - 是否已知代码优先 EF 无法与包含大量 DbSet 的 DbContext 一起使用?