0

I access data in a database through a Web-Api and send it back as Json string to an UWP-App.

MessageRepository.cs:

public List<Message> GetByRecipientId(int id)
{
   var listOfMsg = new List<Message>();
   using (var ctx = new ShowcaseContext())
   {
      var recipientWithId = ctx.Recipients.Where(rec => rec.UserId == id);

      foreach (var recipient in recipientWithId.ToList())
      {
         var msgWithId = ctx.Messages.Where(msg => msg.Id == recipient.MessageId);
         listOfMsg.Add(msgWithId.Single());
      }

      return listOfMsg;
   }
}

MessageController.cs:

[Route("api/message/recipient/{id}")]
public IEnumerable<Message> GetByRecipientId(int id)
{
   return messageRepository.GetByRecipientId(id);
}

The problem is that I'm getting an

"Newtonsoft.Json.JsonSerializationException" Error

when trying to return listOfMsg to the UWP-App.
But if I look at the List<> and it items in debug mode, or access a specific message in the List<> before returning it, the error disappeares and I get the right data in the UWP-App.
It seems like the List<> has a different format before accessing it specifically which can't be serialized.
Has anyone an idea why?

Edit
Message.cs:

public class Message
{
    public int Id { get; set; }
    public virtual Collection<Recipient> Recipients { get; set; }
    public MessageTrigger Trigger { get; set; }
    public string Body { get; set; }
    public DateTime CreatedTs { get; set; }
}

The StackTrace is null, but the error message is

The "ObjectContent`1" type failed to serialize the response body for content type "application/json; charset=utf-8".

croxy
  • 3,641
  • 8
  • 25
  • 42

1 Answers1

2

Most probably you have lazy loading enabled. That means that when you access a navigation property, EF will try to hit the database to get the related entity, and this will work if the DbContext is still "alive".

After the API call returns the data, JSON.NET will visit all the properties to serialize them, including the navigation properties. And, at that point, the DbContext has already been disposed of. That's why you get your error.

To avoid it you can:

For more info on disabling lazy loading.

Alternative: Json configuration

You can also instruct JSON.NET to skip some properties. But there are mabny ways of doing so, and you have to add attributes to your entities. For example:

Alternative: projection to anonymus class with .Select()

And I forgot a final, easy option: you can project your query to an anonymous class, getting read of all problems, and returning the JSON that you exactly want to return.

.Select(new { /* your projection */ });

Although this answers are for older versions, it still works in the same way.

NOTE: while you're debugging you're still inside the DbContext using block, and that's why you don't get errors while debugging. If you put this line: return listOfMsg; outside the using block, add a breakpoint in that line, and watch navigation properties, you'll also get errors in the debugger.

Community
  • 1
  • 1
JotaBe
  • 34,736
  • 7
  • 85
  • 109