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

 等一场-花开花落 发布于 2022-12-04 14:25

我遵循Mike Wasson的这个asp.net教程,设法建立相关实体就好了,但是当我将这个逻辑应用到我的项目时,更复杂的实体关系(其中有更多的实体关系;这是唯一的区别)在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 Console安装6.9.x,而NuGet Dialog安装6.5.x).我也想知道是不是因为我将项目设置为一个完全空的项目然后使用OWIN,所以我尝试使用纯ASP.NET模板解决方案.我还尝试了其他几种可能的解决方案:我的控制器方法上的OData-route-attributes; 并将我的数据层和模型都包含在同一个库中(我将它们分开以保持DRY); 我甚至试图使用Rick Anderson的WebApi路由调试器 - 我不会再尝试使用它了!

一切都无济于事.

有一段时间他们工作,但我不知道为什么; 他们不再在下一次建造/运行中工作 - 我想我之间改变了一些东西,但它非常小,我在每一步都失去了信心.

然后我决定Mike Wasson必须在他的教程中采取阻力最小的路径,所以我回复到这个问题/答案,并将其修改为与ODataConventionModelBuilder一起使用并重用,我将在下面的答案中解释.

如果有人知道更简单的方法让这个工作,请告诉我,否则我建议只是咬紧牙关并在下面的答案中写下这些EdmModel-Navigations.

1 个回答
  • 正如我在问题中提到的那样,我尝试了许多解决方案来实现这一点,但实际上解决问题并没有一致,我一直在避免在这个问题/答案中提出的解决方案,因为该教程专门针对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;
    }
    

    第二个AddNavigations:

    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部分 - 您需要首先遵循第1部分!).

    2022-12-11 02:58 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有