Reputation: 217
Hi community I recenty began learning how to code a web api,
I had a project in winform that I wanted to remake using web api, the thing is I can't use eager loading, I always get error 500, the code is like this:
public HttpResponseMessage GetExpediente()
{
db.Configuration.ProxyCreationEnabled = false;
var expediente = db.Expediente.Include(x=>x.Documento);
if (expediente.Any())
{
return Request.CreateResponse(HttpStatusCode.OK, expediente);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
"No se encontraron expedientes.");
}
}
the error I always get is:
{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Self referencing loop detected for property 'Expediente' with type 'Modelo.Expediente'. Path '[0].Documento[0]'.","ExceptionType":"Newtonsoft.Json.JsonSerializationException","StackTrace":" en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n en Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n en Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n en System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n en System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n en System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n en System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- Fin del seguimiento de la pila de la ubicación anterior donde se produjo la excepción ---\r\n en System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n en System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n en System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"}}
I've been looking for info. that could help me but I always find that I should disable lazyloading, I did, and it didn't work, can anybody here help me?
Btw my objective is to consume this api from a windows form project, someone told me to do this:
var emp1 = response.Content.ReadAsStringAsync().Result;
var result = JsonConvert.DeserializeObject<IEnumerable<ExpedientePOCO>>(emp1);
but what I get from the line of var emp1 = ... is an error 500. Oh and when I take the include from the context, it works just fine, but I want to use Eager loading hope you can help!
Thanks! Regards!
What I understood of DTOs:
public HttpResponseMessage GetExpediente()
{
db.Configuration.ProxyCreationEnabled = false;
var expediente = db.Expediente.Include(x=>x.Documento);
List<ExpedientePOCO> expPOCO = new List<ExpedientePOCO>();
foreach (var entidad in expediente)
{
String fecha = String.Format("{0:dd-MM-yyy}", entidad.FechaCreacion);
ExpedientePOCO expedientePOCO = new ExpedientePOCO()
{
idExpediente = entidad.idExpediente,
NombreExpediente = entidad.NombreExpediente,
FechaCreacion = Convert.ToDateTime(fecha),
DuenioExpediente = entidad.DuenioExpediente,
CantidadDocumento = entidad.CantidadDocumento
};
foreach (var documentos in entidad.Documento)
{
DocumentoPOCO documento = new DocumentoPOCO()
{
idDocumento = documentos.idDocumento,
idExpediente = documentos.idExpediente,
NombreDocumento = documentos.NombreDocumento,
FechaCreacion = documentos.FechaCreacion,
Expedientes = expedientePOCO
};
expedientePOCO.Documentos.Add(documento);
}
expPOCO.Add(expedientePOCO);
}
if (expPOCO.Any())
{
return Request.CreateResponse(HttpStatusCode.OK, expPOCO);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
"No se encontraron expedientes.");
}
}
Upvotes: 1
Views: 686
Reputation: 32068
The problem is, as the error message states, that you have an endless loop, most likely something like this:
public class A
{
public B B { get; set; }
}
public class B
{
public virtual ICollection<A> A { get; set; }
}
So you get A => B => A
endlessly, hence the error. You can solve this by configuring the serializer (ReferenceLoopHandling.Ignore
in NewtonSoft.Json), or by using attributes ([JsonIgnore]
), depending on your specific needs and tools used.
Another solution is to use Data Transfer Objects (DTOs) or similar:
public class ADTO
{
// needed properties only
public BDTO B { get; set; }
}
public class BDTO
{
// needed properties only
public List<ADTO> A { get; set; }
}
And then select into DTOs instead of entities:
var data = db.As
.Select(a => new ADTO
{
x = a.x ....
B = new BDTO { x = a.B.x ... }
}
.ToList();
Or, the other way around:
var data = context.B
.Select(b => new BDTO
{
x = b.x ...
A = b.A
.Select(a => new ADTO
{
x = a.x ...
}
.ToList()
}
.ToList();
Upvotes: 2