我通过OData公开了一个复杂的类型。课程是这样的:
public class RemoteFile
{
[Key]
public int Id { get; set; }
[Required]
public string Resource { get; set; }
public virtual ICollection<RemoteFile> RelatedFiles { get; set; }
}
我通过OData公开它:
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.ComplexType<RemoteFile>();
这是我开始项目时得到的:
System.Web.Http.OData.dll中出现“System.ArgumentException”类型的异常,但未在用户代码中处理
附加信息:复杂类型“RemoteFile”通过属性“RelatedFiles”引用自身。不允许复杂类型的递归循环。
如果存在此异常的处理程序,则可以安全地继续该程序。
欢迎任何建议。
答案 0 :(得分:3)
听起来RemoteFile
更有意义的是实体类型,而不是复杂类型。实体类型可以具有指向原始类型的属性,这就是您设置RemoteFile
的方式。您对类型的定义也有一个键属性,用于实体类型,而不是复杂类型。 (将复杂类型视为对一组标量属性进行分组的便捷方式。实体类型是系统的第一类类型,其中每个实例都可以唯一标识。)
所以不要这样:
modelBuilder.ComplexType<RemoteFile>();
试试这个:
modelBuilder.EntitySet<RemoteFile>(“RemoteFiles”);
该行将创建实体类型RemoteFile
和实体集RemoteFiles
。实体集是实体类型的所有实例的容器。
那么为什么递归允许实体类型而不是复杂类型呢?当您要求实体时,默认情况下,服务器不会获取引用实体的数据。您可以在查询中使用$expand
明确询问引用实体的数据,但无法无限扩展。另一方面,当您要求父母时,将始终包含复杂值。因此,如果您有一个循环复数值,则在尝试序列化时会产生堆栈溢出。
答案 1 :(得分:2)
我遇到了同样的问题。我有一个包含100多个实体的模型,我试图只添加两个,用于make测试。
解决方案:向ODataConventionModelBuilder添加所有实体,如下所示:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entity1>("Entity1");
builder.EntitySet<Entity2>("Entity2");
builder.EntitySet<Entity3>("Entity3");
//... and thus for ALL YOUR ENTITIES.
// If you don't want to expose any entity like EntitySet, simply add to builder like EntityType:
builder.EntityType<Entity4>("Entity4");
即使您不添加实体,构建器也会扫描所有类型(如复杂类型),并且关系会失败。因此,有必要指定所有扫描类型都是实体。
如果您不想公开所有类似的EntitySet,您可以添加到EntityType之类的构建器,并且您的客户端引用将使用此类但不会授予您访问EntitySet(CRUD操作)的权限。此实体只能通过暴露实体的关系间接使用。
答案 2 :(得分:2)
您是否需要明确忽略导航属性?
modelBuilder.ComplexType<RemoteFile>().Ignore(x => x.RemoteFile);
希望有所帮助:)
答案 3 :(得分:0)
错误消息&#34;复杂类型&#39; RemoteFile&#39;通过财产“相关文件”来引用自己。不允许复杂类型的递归循环。&#34;是由于Web API OData库的限制,特别是ODataConventionModelBuilder
类的内部工作原理。对于许多人来说,这是一个阻塞问题,在GitHub上跟踪here。