WebAPI 响应导致 "System.OutOfMemoryException"
WebAPI response causes "System.OutOfMemoryException"
我开发了一个 WebAPI 服务,该服务 returns 在其响应中包含一组复杂的自定义对象。
他们的一些领域有多对多的关系。例如:
[Table("OEReferences", Schema = "public")]
public class OEReference
{
[NotMapped]
public IList<IAReference> IAReferences{ get; set; }
}
[Table("IAReferences", Schema = "public")]
public class IAReference
{
[NotMapped]
public IList<OEReference> OEReferences{ get; set; }
}
每个 OEReference 对象都有一个 IAReferences 列表,同时每个 IAReference 对象都有一个 OEReference 列表(包括第一个)及其对应的 IAReferences 列表,等等。它永远不会停止。
有时我会遇到内存不足的异常。是这个原因吗?我该如何预防?
只有 ~50 个 OEReference,每个 OEReference 都包含几个 IAReference,这已经打破了。其余字段非常简单。
我在 .Net 4.7.1.
中使用 HttpClient class
看起来您正在 returning Entity Framework 直接来自 Web API 的对象(通过其内置的 JSON 序列化程序)。一般规则是永远不要这样做,因为 JSON 序列化程序将尝试序列化它能找到的所有内容。但是对于具有像您这样的关系的 EF 对象,它将不知道在哪里停止,从而导致引用循环错误甚至内存不足错误。
相反,您需要从 EF 对象中准确获取您需要的内容,或者更准确地说:您的 API 调用者需要的内容。
解决方案是创建 Objects/ViewModels 复制调用者需要的 EF 对象部分,填充 EF 对象中的那些部分,然后 return 它们。
一种快速而简单的方法是使用匿名对象,例如:
// Instead of "return EF_Item":
return new
{
Item = new
{
Id = EF_Item.Id,
Description = EF_Item.Description,
Things = MapThings(EF_Item.Things) // helper function that you need to provide
}
};
一个好的经验法则是仅将 EF 对象的简单属性(数字、布尔值、字符串、日期时间)分配给 ViewModel 项。一旦您遇到一个 EF 对象 属性 是另一个 EF 对象(或 EF 对象的集合),您就需要将它们也转换为未链接到 EF 的 'simple' 对象。
一种更结构化的方法是使用 ViewModel 类,您可以使用 AutoMapper 等工具使其更加结构化,该工具(一旦配置)将随时随地为您进行映射它。
我开发了一个 WebAPI 服务,该服务 returns 在其响应中包含一组复杂的自定义对象。 他们的一些领域有多对多的关系。例如:
[Table("OEReferences", Schema = "public")]
public class OEReference
{
[NotMapped]
public IList<IAReference> IAReferences{ get; set; }
}
[Table("IAReferences", Schema = "public")]
public class IAReference
{
[NotMapped]
public IList<OEReference> OEReferences{ get; set; }
}
每个 OEReference 对象都有一个 IAReferences 列表,同时每个 IAReference 对象都有一个 OEReference 列表(包括第一个)及其对应的 IAReferences 列表,等等。它永远不会停止。
有时我会遇到内存不足的异常。是这个原因吗?我该如何预防?
只有 ~50 个 OEReference,每个 OEReference 都包含几个 IAReference,这已经打破了。其余字段非常简单。 我在 .Net 4.7.1.
中使用 HttpClient class看起来您正在 returning Entity Framework 直接来自 Web API 的对象(通过其内置的 JSON 序列化程序)。一般规则是永远不要这样做,因为 JSON 序列化程序将尝试序列化它能找到的所有内容。但是对于具有像您这样的关系的 EF 对象,它将不知道在哪里停止,从而导致引用循环错误甚至内存不足错误。
相反,您需要从 EF 对象中准确获取您需要的内容,或者更准确地说:您的 API 调用者需要的内容。
解决方案是创建 Objects/ViewModels 复制调用者需要的 EF 对象部分,填充 EF 对象中的那些部分,然后 return 它们。
一种快速而简单的方法是使用匿名对象,例如:
// Instead of "return EF_Item":
return new
{
Item = new
{
Id = EF_Item.Id,
Description = EF_Item.Description,
Things = MapThings(EF_Item.Things) // helper function that you need to provide
}
};
一个好的经验法则是仅将 EF 对象的简单属性(数字、布尔值、字符串、日期时间)分配给 ViewModel 项。一旦您遇到一个 EF 对象 属性 是另一个 EF 对象(或 EF 对象的集合),您就需要将它们也转换为未链接到 EF 的 'simple' 对象。
一种更结构化的方法是使用 ViewModel 类,您可以使用 AutoMapper 等工具使其更加结构化,该工具(一旦配置)将随时随地为您进行映射它。