【问题标题】:Can not query a single resource after upgrading JSONAPI.NET to latest version (0.3.0-pre-1)将 JSONAPI.NET 升级到最新版本 (0.3.0-pre-1) 后无法查询单个资源
【发布时间】:2015-02-24 09:37:41
【问题描述】:

将 JSONAPI.NET 升级到最新版本 (0.3.0-pre-1) 后,我无法查询单个资源(即 /{controller}/{id})。我可以查询所有多个资源端点(即 /{controller})。

它可能与JSONAPI.EntityFramework.Http.ApiController 有关,因为我使用System.Web.Http.ApiController 创建了一个控制器并且它工作正常。我使用了相同的 DbContext。

我已经关注/尝试了来自JSONAPI.TodoMVC.API 的所有代码。

这是我得到的错误:

{
"errors": [
    {
        "id": "6b49c8a9-d7b4-473e-80cd-c771fe1e7d13",
        "status": "500",
        "title": "System.AggregateException",
        "detail": "One or more errors occurred.",
        "inner": {
            "id": null,
            "status": "500",
            "title": "System.ArgumentException",
            "detail": "The Type AssetClass was not found in the DbContext with Type ApiContext",
            "inner": {
                "id": null,
                "status": "500",
                "title": "System.ArgumentException",
                "detail": "The member with identity 'ConeTec.DataServices.Web.Areas.WebApi.Models.AssetClass' does not exist in the metadata collection.\r\nParameter name: identity",
                "inner": null,
                "stackTrace": "   at System.Data.Entity.Core.Metadata.Edm.ItemCollection.GetItem[T](String identity, Boolean ignoreCase)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetKeyNames(Type type)"
            },
            "stackTrace": "   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetKeyNames(Type type)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetKeyProperties(Type type)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetByIdAsync(Type type, Object[] idValues)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.<GetByIdAsync>d__0`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at JSONAPI.Http.ApiController`1.<Get>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()"
        }
   }
]

}

知道为什么会出现此错误吗?

谢谢!

S'pht'Kr @S'pht'Kr

csantero @csantero

这是完整的错误跟踪:

{
"errors": [
    {
        "id": "57a5f40e-b170-407f-982a-c7cad64539e9",
        "status": "500",
        "title": "System.AggregateException",
        "detail": "One or more errors occurred.",
        "inner": {
            "id": null,
            "status": "500",
            "title": "System.ArgumentException",
            "detail": "The Type AssetClass was not found in the DbContext with Type ApiContext",
            "inner": {
                "id": null,
                "status": "500",
                "title": "System.ArgumentException",
                "detail": "The member with identity 'ConeTec.DataServices.Web.Areas.WebApi.Models.AssetClass' does not exist in the metadata collection.\r\nParameter name: identity",
                "inner": null,
                "stackTrace": "   at System.Data.Entity.Core.Metadata.Edm.ItemCollection.GetItem[T](String identity, Boolean ignoreCase)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetKeyNames(Type type)"
            },
            "stackTrace": "   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetKeyNames(Type type)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetKeyProperties(Type type)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.GetByIdAsync(Type type, Object[] idValues)\r\n   at JSONAPI.EntityFramework.EntityFrameworkMaterializer.<GetByIdAsync>d__0`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at JSONAPI.Http.ApiController`1.<Get>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()"
        },
        "stackTrace": "   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)\r\n   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)\r\n   at System.Threading.Tasks.Task.Wait()\r\n   at ConeTec.DataServices.Web.Filters.ApiUserContextAttribute.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func`1 continuation) in c:\\CDS\\ConeTecGeoDb\\ConeTec.DataServices.Web\\Filters\\UserContextAttribute.cs:line 160\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
    }
]

}

这是我AssetClassesController的一个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using ConeTec.DataServices.Web.Areas.WebApi.Models;
using JSONAPI.EntityFramework.Http;

namespace ConeTec.DataServices.Web.Areas.WebApi.Controllers {
    public class AssetClassesController : ApiController<AssetClass, ApiContext> {

    }
}

【问题讨论】:

  • 这当然很有趣。如果您尝试具体化不在 DbContext 中的模型类型,则应引发此错误。但是你是说能成功得到/assetclasses/却不能得到/assetclasses/42? AssetClass 是您的 DbContext 中的实体之一吗?或者这是对其他实体的请求的结果,而 AssetClass 是从成员属性返回的非实体类型?
  • 是的,没错。我可以访问/assetclasses/,但不能访问/assetclasses/42。是的,AssetClass 是在我的 DbContext 中定义的。所有实体都有同样的问题。我刚刚创建了一个新的(没有任何关系),我遇到了同样的问题。如果我的控制器继承自 System.Web.Http.ApiController,一切正常。
  • 这很难。我将不得不仔细查看代码,看看我是否有任何想法。我唯一想到的另一件事是导致它无法加载实体元数据。您可以发布您的ApiController 课程,包括您的using 声明吗?
  • 另一个问题...如果模型对象跨项目或程序集,似乎实体框架的潜在错误可能会发生...AssetClass 是否在与您的ApiController 不同的项目中定义?这可能是一个因素。无论是什么原因造成的,都有一种解决方法。创建EntityFrameworkMaterializer 的子类并覆盖GetById 方法。您可以在其中包含逻辑以通过 ID 获取任何模型。失败的是 EFM 试图弄清楚如何自动做到这一点。明天我会发布更详细的答案。
  • 我按要求发布了我的AssetClassesControllerModels/Controllers/ApiContext 都在同一个项目中。都在一个区域内。

标签: asp.net entity-framework json-api


【解决方案1】:

这个错误应该从https://github.com/SphtKr/JSONAPI.NET/pull/77 开始修复。

【讨论】:

    【解决方案2】:

    确保您在 ApiContext 类中将 AssetClass 定义为 DBSet&lt;AssetClass&gt; AssetClass

    【讨论】:

      【解决方案3】:

      好的,我正在空中编码……在我的 iPhone 上……但试试看。

      创建自己的EntityFrameworkMaterializer 子类并覆盖GetKeyNames 方法,如下所示:

      protected override IEnumerable<string> GetKeyNames(Type type)
      {
          this.DbContext.MetadataWorkspace.LoadFromAssembly(this.DbContext.GetType().Assembly);
          return base.GetKeyNames(type);
      }
      

      然后在您的ApiController 覆盖...

      protected override JSONAPI.Core.IMaterializer MaterializerFactory()
      {
          return new MyMaterializer(new ApiContext());
      }
      

      这样做有一些效率低下,但如果这解决了你的问题,那么我可以弄清楚在图书馆里做什么。

      作为备用计划,只需使用重写的 GetKeyNames 方法返回每个模型类型的正确键名列表。 (提示:如果这在 0.2.0 中对您有用,那么每次都可以安全地简单地返回 new List&lt;string&gt; { "Id" }...因为我最近发现这就是旧的 GetKeyNames 方法所能做的全部。);-)

      【讨论】:

      • 感谢 S'pht'Kr。按照您的建议从程序集中加载不起作用。我选择了您的另一个建议,即返回new List&lt;string&gt; { "Id" },它现在正在工作。但是,这似乎不是最佳解决方案;)
      • 不确定是否有帮助,但我的 Web API 位于 Area
      • 不确定它是否与这个问题有关,但我不能在与IncludeInPayload(true) 的表示中包含关系。你觉得有关系吗?没有返回错误,根本不包括在内。
      • 很可能相关,但未知。我正在阅读领域......据我所知,编译器和运行时对它们一无所知,它们严格来说是 MVC 的东西......意思是,EF 甚至不应该知道它们的区别。但我会进一步研究。
      • 我已经覆盖了EntityFrameworkMaterializer.GetKeyNames 以查看System.Data.Entity.Core.Metadata.Edm.DataSpace.OSpace 而不是System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace,我现在可以获得单个资源。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-12
      • 2019-02-15
      • 2017-03-21
      • 1970-01-01
      • 2012-04-21
      相关资源
      最近更新 更多