ef4 causa Referencia circular en el servicio web

Tengo un objeto Reason:

public class Reason { public virtual long Id { get; set; } public virtual string Name { get; set; } public virtual Company Company {get;set;} } 

Estoy utilizando entity framework 4 y Company es propiedad de navegación de la empresa.
También uso webservices para devolver datos al cliente.
Tengo un método web que devuelve razones:

  [WebMethod] public Reason[] GetCallReasons() { IReasonRepository rep = ObjectFactory.GetInstance(); return rep.GetReasonsList().ToArray(); } 

Debido al ef4, recibo la siguiente excepción para ejecutar el método web:

 A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537' 

El problema se produce porque ef4 agrega propiedad que no se puede serializar: Imagen del panel de reloj en rep.GetReasonsList (). ToArray ()

Para resolver esto y eliminar el error, puedo deshabilitar la propiedad de navegación al no hacerla virtual o eliminar la propiedad de navegación. Pero lo necesito y quiero usar la función de carga diferida.

También puedo escribir el serializador específico para Reason, pero tengo muchas clases que utilicé en mis servicios web y escribo un serializador para todas ellas, es mucho trabajo.

¿Cómo puedo resolver esta excepción?

Existen múltiples soluciones para su problema y realmente dependen del tipo de servicio que esté utilizando y del tipo de serialización:

  • El enfoque limpio está usando DTO (objetos de transferencia de datos) como @Mikael ya sugirió. DTO es un objeto especial que transfiere exactamente lo que necesita y nada más. Simplemente puede crear DTO para que no contengan referencias circulares y usar AutoMapper para mapear entre entidades y DTO y viceversa. +1 para @Mikael porque fue el primero en mencionar esto.

Todos los demás enfoques se basan en la serialización de tweeking como @Haz sugirió:

  • WCF y DataContractSerializer : marque explícitamente sus entidades con DataContract[IsReference=true] y todas las propiedades con atributos [DataMember] . Esto le permitirá usar referencias circulares. Si está utilizando una plantilla T4 para generar entidades, debe modificarla para agregarle estos atributos.
  • WCF y DataContractSerializer : serialización implícita. Marque una de las propiedades de navegación relacionadas con el atributo [IgnoreDataMember] para que la propiedad no se serialice.
  • XmlSerializer : marque una de las propiedades de navegación relacionadas con el atributo [XmlIgnore]
  • Otras serializaciones: marque una de las propiedades de navegación relacionadas con [NonSerialized] (+1 para Haz fue el primero en mencionar esto) para la serialización común o [ScriptIgnore] para alguna serialización relacionada con JSON.

Normalmente escribo clases específicas para el servicio web. Si bien este es un trabajo adicional, tiene la ventaja de que el servicio web se vuelve más robusto ya que los pequeños cambios en sus entidades no pasarán desapercibidos y silenciosamente fallarán en el lado del consumidor / javascript. Por ejemplo, si cambio el nombre de una propiedad.

Hay algunas cosas que puede hacer para reducir el trabajo y una es usar AutoMapper que puede mapear automáticamente entre objetos.

No ha proporcionado la definición para su clase de empresa … Pero supongo que tiene una colección de Reason como propiedad.

La carga lenta en un entorno SOA realmente no funciona. No se puede tener navegación laxa ilimitada en una clase serializada, una vez que se abandona el método web no se puede volver a llamar al contexto de datos original del consumidor del método web para buscar las propiedades adecuadas … entonces el serializador intentará visitar todas las propiedades, incluidas las propiedades perezosas en el momento de la serialización.

Debe inhabilitar la serialización en una parte de la referencia circular, ya sea en la colección Reason de la clase Company o en la clase de la Compañía en Reason.

Puede usar el atributo “NotSerialized” para deshabilitar la serialización de un campo en particular.