【问题标题】:WebApi + OData = Error -> "The property does not belong to the specified type"WebApi + OData = Error -> "该属性不属于指定类型"
【发布时间】:2012-10-06 23:05:00
【问题描述】:

我在 URI 中使用的任何 OData 命令都会显示以下错误!
当我使用没有任何配置/参数 OData 的 api 时,效果很好!
但是任何$filter$top$skip,都会产生以下错误:

代码

ApiController

[Queryable]
public IQueryable<Processo> get()
{
    return _repositorio.Query<Processo>();
}

API 路由

public static void Register(HttpConfiguration config)
{
    // Controller Only -> To handle routes like `/api/pessoas`
    config.Routes.MapHttpRoute(
        name: "ControllerOnly",
        routeTemplate: "api/{controller}"
    );

    // Controller with ID -> To handle routes like `/api/pessoas/1`
    config.Routes.MapHttpRoute(
        name: "ControllerAndId",
        routeTemplate: "api/{controller}/{id}",
        defaults: null,
        constraints: new { id = @"^\d+$" } // Only integers 
    );

    // Controllers with Actions -> To handle routes like `/api/pessoas/getProfissoes`
    config.Routes.MapHttpRoute(
        name: "ControllerAndAction",
        routeTemplate: "api/{controller}/{action}"
    );

    config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
    config.Formatters.Remove(config.Formatters.XmlFormatter);
}

IRepository 查询实现

public IQueryable<T> Query<T>(params Expression<Func<T, object>>[] includeProperties)
    where T : class, IEntity
{
    return includeProperties.Aggregate<Expression<Func<T, object>>, IQueryable<T>>(Set<T>(), (current, includeProperty) => current.Include(includeProperty));
}

[添加] 进程类

public class Processo : IEntity, IAuditable
{
    public DateTime CreateAt { get; set; }
    public string CreateBy { get; set; }
    public DateTime? UpdateAt { get; set; }
    public string UpdateBy { get; set; }

    public int Id { get; set; }

    public DateTime DataEntrada { get; set; }
    public virtual Modalidade Modalidade { get; set; }
    public virtual PassoExecucao PassoAtual { get; set; }

    public string Imovel { get; set; }
    public double ValorFinanciado { get; set; }
    public double ValorVenda { get; set; }
    public double? FGTS { get; set; }

    public virtual Pessoa Comprador { get; set; }
    public virtual Pessoa Proprietario { get; set; }

    public virtual Agencia Agencia { get; set; }
    public virtual Empresa Despachante { get; set; }
    public virtual Empresa Originador { get; set; }

    public virtual ICollection<File> Arquivos { get; set; }
    public virtual ICollection<Historico> Historicos { get; set; }
}

尝试

  1. 网址:/api/processos?$filter=Id eq 1 同样的错误
  2. 网址:/api/processos?$skip=1 同样的错误
  3. 网址:/api/processos 没有错误!!

[添加] 做一些测试。发现只发生在引用 Person 类的地方。

public class Pessoa : IEntity, IAuditable
{
    public int Id { get; set; }

    public DateTime CreateAt { get; set; }
    public string CreateBy { get; set; }
    public DateTime? UpdateAt { get; set; }
    public string UpdateBy { get; set; }

    public string Nome { get; set; }
    public DateTime? DataNascimento { get; set; }
    public GeneroEnum Genero { get; set; }
    public virtual TipoPessoa Tipo { get; set; }
    public virtual Pessoa Conjuge { get; set; }

    public virtual Nacionalidade Nacionalidade { get; set; }
    public string Naturalidade { get; set; }
    public virtual Profissao Profissao { get; set; }
    public string Empresa { get; set; }
    public double? RendaBrutaMensal { get; set; }
    public DateTime? DataInicioEmpresa { get; set; }
    public DateTime? DataReferenciaEmpresa { get; set; }
    public EscolaridadeEnum Escolaridade { get; set; }

    public string CPF { get; set; }
    public string PIS { get; set; }
    public string RG { get; set; }
    public string OrgaoExpedidor { get; set; }
    public string TipoDocumento { get; set; }
    public DateTime? DataEmissao { get; set; }

    public EstadoCivilEnum? EstadoCivil { get; set; }
    public RegimeCasamentoEnum? RegimeCasamento { get; set; }
    public bool? ComposicaoRenda { get; set; }
    public bool? UniaoEstavel { get; set; }

    public virtual ICollection<Telefone> Telefones { get; set; }
    public virtual ICollection<Endereco> Enderecos { get; set; }
    public virtual ICollection<Email> Emails { get; set; }
}

错误

使用 Processo 类

[Queryable]
public IQueryable<Processo> get()
{
    return _repositorio.Query<Processo>();
}

{
    "$id": "1",
    "Message": "An error has occurred.",
    "ExceptionMessage": "The property does not belong to the specified type.\r\nParameter name: navigationProperty",
    "ExceptionType": "System.ArgumentException",
    "StackTrace": "   at System.Web.Http.OData.Builder.EntityTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity)\r\n   at System.Web.Http.OData.Builder.ODataConventionModelBuilder.MapEntityType(IEntityTypeConfiguration entity)\r\n   at System.Web.Http.OData.Builder.ODataConventionModelBuilder.AddEntity(Type type)\r\n   at System.Web.Http.OData.Builder.EntityTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity)\r\n   at System.Web.Http.OData.Builder.ODataConventionModelBuilder.MapEntityType(IEntityTypeConfiguration entity)\r\n   at System.Web.Http.OData.Builder.ODataConventionModelBuilder.MapTypes()\r\n   at System.Web.Http.OData.Builder.ODataConventionModelBuilder.GetEdmModel()\r\n   at System.Web.Http.HttpActionDescriptorExtensions.<>c__DisplayClass1.<GetEdmModel>b__0(Object _)\r\n   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)\r\n   at System.Web.Http.HttpActionDescriptorExtensions.GetEdmModel(HttpActionDescriptor actionDescriptor, Type entityClrType)\r\n   at System.Web.Http.QueryableAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.CallOnActionExecuted(HttpActionContext actionContext, HttpResponseMessage response, Exception exception)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<>c__DisplayClass2.<System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync>b__0(HttpResponseMessage response)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass41`2.<Then>b__40(Task`1 t)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)"
}

使用佩索阿类

[Queryable]
public IQueryable<Pessoa> get()
{
    return _repositorio.Query<Pessoa>();
}


{
    "$id": "1",
    "Message": "An error has occurred.",
    "ExceptionMessage": "An item with the same key has already been added.",
    "ExceptionType": "System.ArgumentException",
    "StackTrace": "   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)\r\n   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)\r\n   at System.Web.Http.OData.Builder.EdmTypeBuilder.<GetEdmTypes>d__0.MoveNext()\r\n   at System.Linq.Enumerable.<OfTypeIterator>d__aa`1.MoveNext()\r\n   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)\r\n   at System.Web.Http.OData.Builder.EdmModelHelperMethods.BuildEdmModel(String containerNamespace, String containerName, IEnumerable`1 entityTypeConfigurations, IEnumerable`1 entitySetConfigurations)\r\n   at System.Web.Http.OData.Builder.ODataModelBuilder.GetEdmModel()\r\n   at System.Web.Http.OData.Builder.ODataConventionModelBuilder.GetEdmModel()\r\n   at System.Web.Http.HttpActionDescriptorExtensions.<>c__DisplayClass1.<GetEdmModel>b__0(Object _)\r\n   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)\r\n   at System.Web.Http.HttpActionDescriptorExtensions.GetEdmModel(HttpActionDescriptor actionDescriptor, Type entityClrType)\r\n   at System.Web.Http.QueryableAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.CallOnActionExecuted(HttpActionContext actionContext, HttpResponseMessage response, Exception exception)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<>c__DisplayClass2.<System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync>b__0(HttpResponseMessage response)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass41`2.<Then>b__40(Task`1 t)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)"
}

【问题讨论】:

  • 您可以发布Processo 对象的代码吗?以及您尝试过的一个/一些 OData 查询?
  • 您运行的是 webapi 版本还是更早的版本?另外,如果去你的包管理控制台并在列表中输入Get-PackageMicrosoft.AspNet.WebApi.OData 0.1.0-alpha-120815
  • 另外,如果您执行 'URL Attempt' #1 ($filter=id eq 1234),错误消息是否与您发布的相同?您发布的错误消息看起来就像您在 api/processos?$id=1 所做的一样(顺便说一句,您的模型有一个大写字母)。
  • 您能否尝试我们的夜间构建,看看它是否已在最新代码中修复?在 nuget 包控制台中使用命令:update-package Microsoft.AspNet.WebApi.OData -IncludePrerelease -source myget.org/F/aspnetwebstacknightly

标签: .net-4.0 asp.net-mvc-4 asp.net-web-api odata


【解决方案1】:

OData 需要您为 Pessoa 类指定主键的概念。通过添加属性来做到这一点:

[DataServiceKey("Id")]
public class Pessoa : IEntity, IAuditable
{
    public int Id { get; set; }
    //...
}

或者通过显式构建您的模型并指定密钥,如 OData Web API 发布博文http://blogs.msdn.com/b/alexj/archive/2012/08/15/odata-support-in-asp-net-web-api.aspx“设置您的模型”标题部分中所述。

【讨论】:

    【解决方案2】:

    这个答案是对聊天中发生的事情的总结。所以它读起来与标准答案不同。


    我没有具体收到此错误,但 OData 似乎无法找到“id”属性。一旦 oData 被提取到一个独立的包中,就会发生一些变化。

    版本?
    我要检查的第一件事是你是否有独立的 oData 包(Microsoft.Data.OData 5.0.1Microsoft.AspNet.WebApi.OData 0.1.0-alpha-120815)。您可以通过在包管理控制台中输入Get-Package 来完成此操作。

    您在聊天中发布了这些:

    Microsoft.AspNet.WebApi.OData 0.1.0-alpha-120815
    Microsoft.Data.Edm 5.1.0-rc2
    Microsoft.Data.OData 5.1.0-rc2
    Microsoft.Data.OData.Contrib 5.1.0.50918-rc
    System.Spatial 5.1.0-rc2

    所以看起来您仍在运行产品的 RC。 is an old bug 似乎描述了这种行为。该错误的缺点是具有继承属性的类会引发错误。

    电流不行
    更新到当前版本似乎并不能解决问题。所以下一步是尝试更新的签名睡衣。

    获取签名的夜间构建的说明are here

    签名的夜间构建解决了问题。

    另一个想法

    在 oData 发生更改后,产品需要能够识别关键属性。 This article 状态

    不知何故,[Queryable] 属性必须找到一个关键属性。这 如果您的元素类型具有 ID 属性,则自动发生,否则 您可能需要手动配置模型(请参阅设置您的 型号)。

    如果您使用的是实体框架,那么人员对象是否定义了实体键?如果没有,您可以尝试“设置模型部分”中指定的oDataConventionModelBuilder。比如:

    ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
    var pessoa= modelBuilder.EntitySet<Pessoa>("Pessoa"); 
    
     pessoa..HasKey(p => p.Id); 
     ...
    

    【讨论】:

      猜你喜欢
      • 2015-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-27
      • 2013-06-27
      • 1970-01-01
      • 2021-01-09
      相关资源
      最近更新 更多