【问题标题】:Getting related entities ASP.NET WebApi OData v4 results in "No HTTP resource was found that matches the request URI"获取相关实体 ASP.NET WebApi OData v4 导致“未找到与请求 URI 匹配的 HTTP 资源”
【发布时间】:2015-02-18 13:23:13
【问题描述】:

我关注this asp.net tutorial by Mike Wasson,并设法很好地设置了相关实体,但是当我将此逻辑应用于我的项目时,更复杂的实体关系(因为它们更多;这是唯一的区别)不会如果 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-route-attributes;并将我的数据层和模型都包含在同一个库中(我将它们分开以保持干燥);我什至尝试使用the WebApi route debugger by Rick Anderson - 我不会再尝试使用它!

一切都无济于事。

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

然后我决定 Mike Wasson 在他的教程中一定是走上了阻力最小的道路,所以我恢复到 this SO question/answer 并对其进行了修改以用于 ODataConventionModelBuilder 和重用,正如我将在下面的回答中解释的那样。

如果有人知道实现此功能的更简单方法,请告诉我,否则我建议硬着头皮在下面的答案中编写那些 EdmModel-Navigations。

【问题讨论】:

    标签: c# asp.net asp.net-web-api odata


    【解决方案1】:

    正如我在问题中提到的,我尝试了许多解决方案来使其正常工作,但在实际解决问题方面没有一个是一致的,我一直避免使用 this SO question/answer 中列出的解决方案,因为本教程专门针对 v4 和我认为答案必须针对旧版本(多么不明智)。

    所以这个答案确实解决了问题,但需要一些工作才能直接适应 OData v4 和 ODataConventionModelBuilder;这就是我发布这个问题和答案的原因;提供一个解决方案,专门针对 OData v4 和 ODataConventionModelBuilder,希望其他人不会浪费我研究这个的时间。

    首先,设置您的 EdmModel:

    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;
    }
    

    第二次添加导航:

    private static void AddNavigations(IEdmModel edmModel)
    {
        AddMenuPermissionsNavigation(edmModel);
    }
    
    private static void AddMenuPermissionsNavigation(IEdmModel edmModel)
    {
        var menus = (EdmEntitySet) edmModel.EntityContainer.FindEntitySet("Menus");
        var menuPermissions = (EdmEntitySet)edmModel.EntityContainer.FindEntitySet("MenuPermissions");
        var menuType = (EdmEntityType) edmModel.FindDeclaredType("iiid8.cms.data.models.Menu"); //"iiid8.cms.data.models" is the C# namespace
        var menuPermissionType = (EdmEntityType)edmModel.FindDeclaredType("iiid8.cms.data.models.MenuPermission"); //as above, "iiid8.cms.data.models" is the C# namespace
        AddOneToManyNavigation("MenuPermissions", menus, menuPermissions, menuType, menuPermissionType);
        AddManyToOneNavigation("Menu", menus, menuPermissions, menuType, menuPermissionType);
    }
    
    private static void AddOneToManyNavigation(string navTargetName, EdmEntitySet oneEntitySet, EdmEntitySet manyEntitySet,
        EdmEntityType oneEntityType, EdmEntityType manyEntityType)
    {
        var navPropertyInfo = new EdmNavigationPropertyInfo
        {
            TargetMultiplicity = EdmMultiplicity.Many,
            Target = manyEntityType,
            ContainsTarget = false,
            OnDelete = EdmOnDeleteAction.None,
            Name = navTargetName
        };
        oneEntitySet.AddNavigationTarget(oneEntityType.AddUnidirectionalNavigation(navPropertyInfo), manyEntitySet);
    }
    
    private static void AddManyToOneNavigation(string navTargetName, EdmEntitySet oneEntitySet, EdmEntitySet manyEntitySet,
        EdmEntityType oneEntityType, EdmEntityType manyEntityType) {
        var navPropertyInfo = new EdmNavigationPropertyInfo {
            TargetMultiplicity = EdmMultiplicity.One,
            Target = oneEntityType,
            ContainsTarget = false,
            OnDelete = EdmOnDeleteAction.None,
            Name = navTargetName
        };
        manyEntitySet.AddNavigationTarget(manyEntityType.AddUnidirectionalNavigation(navPropertyInfo), oneEntitySet);
    }
    

    最后,从 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 部分 - 您首先需要 follow Part 1!)。

    【讨论】:

      【解决方案2】:

      我正在使用 ASP.NET 5、Web API 2.2 和实体框架。

      另一位开发人员和我也花了好几个小时试图弄清楚为什么在遵循相同的 T 教程之后,我们无法获得如下关系路由来返回 404 以外的任何内容:

      /odata/Supplier(1)/Products
      

      我们还尝试了 OP 中引用的路由调试器,但除了空白屏幕之外,它没有产生任何东西。

      幸运的是,根据我们的需要,我们的一项随机实验奏效了,那就是使用 ODataRoute 属性,如下所示:

          [EnableQuery]
          [ODataRoute("Suppliers({key})/Products")]
          public IQueryable<Product> GetProductsForSupplier([FromODataUri] int key)
          {
              ...
          }
      

      【讨论】:

      • 几天前我赞成这个答案,但没有时间发表评论;这当然是让它工作的更简单的解决方案,本质上,这是我最初的问题,但我不认为它是大型项目的可扩展、可靠的解决方案,因为任何使用实体的路线都需要用属性。对于想要启动和运行而无需当前接受的答案中概述的工作开销的小型项目,这仍然是一个很好的解决方案。如果大家一致认为我应该将已接受的答案更改为这个答案,那么我很乐意这样做。
      • 我认为这更像是一种解决方法,而不是正确答案。所以,我认为现在一切都很好!不过,谢谢。
      • 对不起,作为一个社区,我们不能接受完全绕过默认功能的解决方案作为最佳解决方案。我同意很难找到关于其中一些内容的最新文档,但这通常是因为我们提出了错误的问题。 OData 默认约定是您将方法命名为 GetProducts - 请参阅获取相关实体:asp.net/web-api/overview/odata-support-in-aspnet-web-api/…
      • 另外,如果 ODataRoute 真的被认为是规避,那么它应该从库中删除。
      • @ChrisSchaller 谈到这个解决方案被社区认为是最好的;我不明白他的意思。这个答案可能会帮助其他人,但它不是公认的答案,也不是投票最多的答案(因此,社区并不是说它是最好的),但它对那些没有的人很有用遵循惯例(正如他正确指出的那样,这并不容易学习)。 他的评论可能会误导人们认为问题中的问题归结为不遵循惯例。做出这个假设是错误的。我赞成这个答案。
      猜你喜欢
      • 2018-09-02
      • 2016-01-26
      • 1970-01-01
      • 2017-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多