0

In my WebApi controller I have a few methods that return objects retrieved from a database which are serialized to Json. Everything works fine if a method serializes and returns only a single object, it fails when it tries to serialize a collection of objects.

This is my model class:

    [Table("Athlete")]
    public partial class Athlete
    {
        public Athlete()
        {
            Event = new HashSet<Event>();
            User = new HashSet<User>();
        }

        [Required]
        [StringLength(32)]
        [DisplayName("First name")]
        public string FirstName { get; set; }

        [Required]
        [StringLength(32)]
        [DisplayName("Last name")]
        public string LastName { get; set; }

        [StringLength(32)]
        [DisplayName("Sport")]
        public string Sport { get; set; }

        [Key]
        [Column(TypeName = "numeric")]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public decimal Athlete_ID { get; set; }

        [DataMember]
        [Column(TypeName = "numeric")]
        public decimal? Team_Team_ID { get; set; }

        [NotMapped]
        [DisplayName("Team")]
        public string TeamName { get; set; }

        [JsonIgnore]
        public virtual Team Team { get; set; }

        [JsonIgnore]
        public virtual ICollection<Event> Event { get; set; }

        [JsonIgnore]
        public virtual ICollection<User> User { get; set; }
    }

This works fine:

[HttpGet]
public IHttpActionResult GetById(int id)
{
    var athlete =  _db.Athlete
        .Where(a => a.Athlete_ID == id)
        .FirstOrDefault();

    if (athlete != null)
    {
        return Json<Athlete>(athlete);
    }

    return NotFound();
}

The following method causes a serialization error (System.InvalidOperationException) (The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.)

The inner exception's message is "Self referencing loop detected for property 'ApplicationInstance' with type 'ASP.global_asax'. Path 'Request.Properties.MS_HttpContext.ApplicationInstance.Context'."

[HttpGet]
public IHttpActionResult GetAllAthletes()
{
    var athletes = _db.Athlete.ToArray();

    if (athletes != null)
    {            
        return Ok(Json<IEnumerable<Athlete>>(athletes));
    }

    return NotFound();
}

I've already tried to change the serialization settings in WebApiConfig.cs like in this question but nothing has worked so far.

Any help would be appreciated.

Community
  • 1
  • 1
rafaLiusz
  • 33
  • 1
  • 5
  • Have you tried to assign the result of the `Json<>()` call to a variable and pass that to `Ok`? – Bernhard Döbler Aug 16 '15 at 11:15
  • 1
    Just tried it. It throws the same exception. – rafaLiusz Aug 16 '15 at 11:39
  • 1
    I finally tried it myself - in Visual Basic in Visual Studio 2015 - and got the same error. I removed the `OK` wrapped around the `Json` and got a result. The server returned a JSON object and HTTP Status 200. Why would you want to wrap it in OK yourself? – Bernhard Döbler Aug 22 '15 at 19:27
  • 1
    Thanks for the tip. In this simplified scenario it would indeed be sufficient to simply wrap an Enumerable<> around the Json. However, with this approach you cannot return any other status than 200. My class could be slightly tweaked so it can return other statuses as well, though. – rafaLiusz Aug 25 '15 at 13:05

1 Answers1

0

I've managed to find a way to work-around this in a semi-elegant manner. I'm not completely happy with this but a man's gotta do what a man's gotta do.

In case anyone needs this in the future:

Create a class that implements the IHttpActionResult interface:

public class MyJsonResult : IHttpActionResult
    {
        object _value;
        HttpRequestMessage _request;

        public MyJsonResult(object value, HttpRequestMessage request)
        {
            _value = value;
            _request = request;
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            var response = new HttpResponseMessage()
            {
                Content = new StringContent(JsonConvert.SerializeObject(_value), Encoding.UTF8, "application/json"),
                RequestMessage = _request,
                StatusCode = HttpStatusCode.OK
            };

            return Task.FromResult(response);
        }
    }

Then use it in a following way:

[HttpGet]
public IHttpActionResult GetAllAthletes()
{
    var athletes = _db.Athlete;

    if (athletes != null)
    {
        return new MyJsonResult(athletes, Request);
    }

    return NotFound();
}
rafaLiusz
  • 33
  • 1
  • 5