C# 获取相关实体ASP.NET WebApi OData v4会导致;找不到与请求URI匹配的HTTP资源;

C# 获取相关实体ASP.NET WebApi OData v4会导致;找不到与请求URI匹配的HTTP资源;,c#,asp.net,asp.net-web-api,odata,C#,Asp.net,Asp.net Web Api,Odata,我遵循了这一点,并成功地设置了相关的实体,但是当我将此逻辑应用到我的项目中时,更复杂的实体关系(因为实体关系更多;这是唯一的区别)在OData调用中不会成功,我得到了一个404,其中包含以下有效负载: { "error": { "code": "", "message": "No HTTP resource was found that matches the request URI 'http://localhost:19215/Menus(c94f7f98-6987-e4

我遵循了这一点,并成功地设置了相关的实体,但是当我将此逻辑应用到我的项目中时,更复杂的实体关系(因为实体关系更多;这是唯一的区别)在OData调用中不会成功,我得到了一个404,其中包含以下有效负载:

{
  "error": {
    "code": "",
    "message": "No HTTP resource was found that matches the request URI 'http://localhost:19215/Menus(c94f7f98-6987-e411-8119-984be10349a2)/MenuPermissions'.",
    "innererror": {
      "message": "No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'.",
      "type": "",
      "stacktrace": ""
    }
  }
}
本教程没有提到必须设置EdmModel导航,Mike Wasson指出“asp.net是官方文档:-”);因此,我花了一段时间试图让这些相关实体工作,认为我设置的项目不正确

我认为这可能与NuGet安装的ASP.NET OData库版本有关(NuGet控制台安装6.9.x,而NuGet对话框安装6.5.x)。我还想知道这是否是因为我将项目设置为一个完全空的项目,然后使用OWIN,所以我尝试使用纯ASP.NET模板解决方案。我还尝试了其他几种可能的解决方案:控制器方法上的OData路由属性;将我的数据层和模型都放在同一个库中(我将它们分开以保持干燥);我甚至尝试过使用-我不会再尝试使用这个了

都没有用

他们工作的时间很短,但我不知道为什么;他们停止了下一次构建/运行的工作-我想我在这两者之间做了一些改变,但这很小,我在每一步都失去了信心

然后我决定Mike Wasson一定是在他的教程中选择了阻力最小的路径,所以我恢复并修改了它,以便与ODataConventionModelBuilder一起使用和重用,我将在下面的回答中解释


如果有人知道一种更简单的方法来实现这一点,请让我知道,否则我建议咬紧牙关,在下面的回答中写下这些EdmModel导航。

正如我在问题中提到的,我尝试了许多解决方案来实现这一点,但在实际解决问题时没有一个是一致的,我一直避免使用中列出的解决方案,因为本教程是专门针对v4的,我认为答案一定是针对较旧的版本(多么不明智)

所以这个答案确实解决了问题,但是需要一些工作来直接适应ODataV4和ODataConventionModelBuilder;这就是为什么我发布了这个问题和答案;为OData v4和ODataConventionModelBuilder提供一个解决方案,希望其他人不会浪费我研究这个问题的时间

首先,设置您的模型:

private static IEdmModel GetEdmModel()
{
    var builder = new ODataConventionModelBuilder();
    builder.EnableLowerCamelCase();
    builder.EntitySet<Menu>("Menus");
    builder.EntitySet<MenuPermission>("MenuPermissions");
    var edmModel = builder.GetEdmModel();
    AddNavigations(edmModel); //see below for this method
    return edmModel;
}
最后,从WebApiConfig.Register调用GetEdmModel

config.MapODataServiceRoute("odata", null, GetEdmModel());
现在从您的客户机调用OData服务的一对多和多对一导航,您的世界应该会一切顺利。在我的例子中,这些调用如下所示:

一对多:

http://localhost:19215/Menus(c94f7f98-6987-e411-8119-984be10349a2)/MenuPermissions
多对一:

http://localhost:19215/MenuPermissions(ba0da52a-6c87-e411-8119-984be10349a2)/Menu

这个答案假设您按照问题中链接的教程中Mike Wasson的建议设置了项目的其余部分(链接到第3部分-您需要首先设置!)。

我使用的是ASP.NET 5、Web API 2.2和实体框架

另一位开发人员和我也花了数小时试图弄明白,在完成了相同的教程之后,为什么我们不能得到一个像下面这样的关系路由来返回404以外的任何东西:

/odata/Supplier(1)/Products
我们还尝试了OP中引用的路由调试器,但它除了生成一个空白屏幕外,没有生成任何其他内容

幸运的是,出于我们的需要,我们的一个随机实验成功了,那就是使用ODataRoute属性,如下所示:

    [EnableQuery]
    [ODataRoute("Suppliers({key})/Products")]
    public IQueryable<Product> GetProductsForSupplier([FromODataUri] int key)
    {
        ...
    }
[启用查询]
[ODataRoute(“供应商({key})/产品”)]
供应商的公共IQueryable GetProducts([FromODataUri]int键)
{
...
}

几天前我对这个答案投了赞成票,但没有时间发表评论;这当然是一个更简单的解决方案来实现这一点,本质上,这是我最初的问题,但我不认为这是一个可扩展的、可靠的解决方案,适用于更大的项目,因为任何使用实体的路由都需要用属性修饰。这仍然是一个很好的解决方案,适用于那些希望启动并运行的小型项目,而不需要当前公认答案中列出的工作开销。如果有一个共识,我应该改变这个问题的答案,那么我会很乐意地这样做。我会认为这更多的是一个解决办法而不是正确的答案。所以,我认为现在一切都很好!不过,谢谢。对不起,伙计们,作为一个社区,我们不能接受一个完全绕过默认功能的解决方案作为最佳解决方案。我同意很难找到关于其中一些的好的最新文档,但这通常是因为我们问了错误的问题。OData的默认约定是将方法命名为GetProducts-请参阅获取相关实体:另外,如果ODataRoute确实被认为是规避,则应将其从库中删除。@Chrischaller谈到此解决方案被社区视为最佳解决方案;我不明白他的意思。这个答案可能会帮助其他人,但它不是公认的答案,也不是得票最多的答案(因此,社区并没有说它是最好的),但它对那些没有遵守惯例的人很有用(正如他正确指出的那样,这不容易学会)。他的评论可能会误导人们,以为问题的症结在于不遵守惯例。做出这样的假设是错误的。我对这个答案投赞成票。
    [EnableQuery]
    [ODataRoute("Suppliers({key})/Products")]
    public IQueryable<Product> GetProductsForSupplier([FromODataUri] int key)
    {
        ...
    }