使用带有外键的对象的WEB API Controller返回JSON

时间:2012-11-05 16:44:40

标签: asp.net-mvc json rest asp.net-web-api

我的代码有问题。 我有一些基本的WEB API控制器工作正常(三个字段没有任何外键),但我有一个问题,API控制器返回模型中的对象列表,并且该类有一个外键到另一个类来自模型。 这会引发错误: 这是Api控制器:

Public Class MaestroProvinciaController
    Inherits System.Web.Http.ApiController

    Private db As New UnificadorEntities

    ' GET api/MaestroProvincia
    Function GetMaestroProvincias() As IEnumerable(Of MaestroProvincia)
        Dim l As IEnumerable(Of MaestroProvincia)
        l = db.MaestroProvincia.AsEnumerable()
        Return l
    End Function
End Class

这是MaestroProvincia的模型

Partial Public Class MaestroProvincia
  Public Property Codigo As Integer
  Public Property Descripcion As String
  Public Overridable Property Usuario As ICollection(Of Usuario) = New HashSet(Of Usuario)

End Class

当我从浏览器到此地址消费时,尝试: ......../api/maestroprovincia

我收到了一个错误: Error del servidor El sistema encontró un error mientras extraía ......../api/maestroprovincia . Es posible que el servidor no esté disponible por mantenimiento o no esté bien configurado. A continuación se detallan algunas sugerencias: Volver a cargar esta página web después. Error HTTP 500 (Internal Server Error): Se encontró una situación inesperada mientras el servidor intentaba cumplir con la solicitud.

当我调试Controller时,在"l"变量中放入一个WATCH(inspect),列表对象的类型很奇怪,而不是MaestroProvincia类型我得到{{ 1}}。

从没有FK的模型返回对象的所有其他API控制器没有任何问题。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

看起来您正在使用EF模型优先或数据库优先方法。 EF返回动态代理,允许您通过使用外键来延迟加载依赖表。您无法序列化动态代理,这是API返回结果所必需的。直接返回EF实体通常不是一个好习惯。您应该使用纯data transfer objects (DTO)POCOS

纯粹的POCOS我指的是你自己定义的类,它们模仿实体但只返回客户端所需的数据。您不能使用EF生成的POCOS使用T4模板,因为有时它们是纯POCOS,有时它们是动态代理。将实体转换为DTO的方法是使用与实体中属性相同的名称创建一个类,并仅包括客户端使用的那些属性。我通常将DTO放在一个单独的命名空间中,以区别于实体。然后使用Automapper自动将实体映射到DTO,将DTO映射到返回的实体。 Automapper将苦差事带出了映射过程。只用一行代码创建地图:

Mapper.CreateMap<Entity.MaestroProvincia, DTO.MaestroProvincia>();

然后它只需要另一行代码来执行实际的映射:

DTO.MaestroProvincia dto = Mapper.Map<Entity.MaestroProvincia, DTO.MaestroProvincia>(maestroProvincia);

答案 1 :(得分:0)

这些是由Entityy Framework创建的代理,以方便延迟加载。但它将拥有您的域模型所具有的所有功能。您应该做的是从这些类中读取数据并将ViewModel(POCO类)返回给公共世界。将您的域名模型返回到公共世界是一个好主意。人们可以从中弄清楚你的桌子是怎么样的。

创建ViewModels( POCO类 ),以便将数据返回到外部世界。只有返回所需的财产。您不需要在viewmodel中拥有域模型的所有属性。稍后从您的数据访问中获取数据,读取项目,将其映射到viewmodel的实例并返回该项目。

List<Mastero> masteroList=new List<Mastero>();
var domainItems=db.MaestroProvincia.AsEnumerable();
foreach(var item in domainItems)
{
  var vm=new Mastero();
  vm.Name=item.Name;
  vm.Description=item.Description;
  masteroList.Items.Add(vm);
}  
 //Now return masteroList to the public

假设Mastero是POCO类,则是您的viewmodel。

public class Mastero
{
  public string Name { set;get;}
  public string Description { set;get;}
}