2

I am very new to asp.net and C# so bear with me. I am trying to return data from a database using the entity framework .include() method so that I can get the foreign key information from another table. However, what is being returned is only part of the data. It seems to be cut off before everything is returned.

"[{"id":11,"name":"Mr. Not-so-Nice","heroType":3,"heroTypeNavigation":{"id":3,"type":"Villian","heroes":["

Which gives me the error: SyntaxError: Unexpected end of JSON input.

Please seem below for the model classes and the GET section of the controller where this is being returned. If I remove the "include()" method it returns all the heroes from the main table just fine.

public partial class Hero
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? HeroType { get; set; }

    public virtual HeroTypes HeroTypeNavigation { get; set; }
}

{
public partial class HeroTypes
{
    public HeroTypes()
    {
        Heroes = new HashSet<Hero>();
    }

    public int Id { get; set; }
    public string Type { get; set; }

    public virtual ICollection<Hero> Heroes { get; set; }
}

// GET: api/Heroes
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Hero>>> GetHeroesTable()
    {
        return await _context.HeroesTable.Include(hero => hero.HeroTypeNavigation).ToListAsync();   
    }
1
  • My guess would be that you need a [JsonIgnore] on your Heroes property of HeroTypes. Each Hero has a HeroType which has a collection of Heroes which each have a HeroType with a collection of Heroes, etc. Basically, the JSON serializer has to step through that recursive mess to get to the end of what it's trying to generate. Commented Mar 7, 2019 at 2:03

1 Answer 1

2

Serializer recursion rules will be tripping this up. Basically as jonsca mentions, you have a circular reference between hero, and hero type. The serializer will start with the hero, then go to serialize the hero type which it will find the Hero's collection and expect to serialize, which each would reference a hero type, with collections of Heros.. The serializer bails when it sees this.

I would recommend avoiding passing back Entity classes to your view to avoid issues with EF and lazy loading. Serialization will iterate over properties, and this will trigger lazy loads. To avoid this, construct a view model for the details your view needs, flatten as necessary.

For example if you want to display a list of Heroes with their Type:

public class HeroViewModel
{
    public int HeroId { get; set; }
    public string Name { get; set; }
    public string HeroType { get; set; }
}

to load:

var heroes = await _context.HeroesTable.Select(x => new HeroViewModel
{
    HeroId = x.HeroId,
    Name = x.Name,
    HeroType = x.HeroType.Type
}).ToListAsync();

You can utilize Automapper for example to help translate entities to view models without that explicit code using ProjectTo<TEntity> which can work with EF's IQueryable implementation.

  • With larger realistic domains your client likely won't need everything in the object graph.
  • You won't expose more information than you need to. (I.e. visible via debugging tools)
  • You'll get a performance boost from not loading the entire graph or triggering lazy load calls, and it's less data across the wire.

The last point is a rather important one as with complex object graphs, SQL can do a lot of the lifting resulting in a much more efficient query than loading "everything". Lazy hits to the database can easily add several seconds to each and every call from a client, and loading large graphs has a memory implication on the servers as well.

Sign up to request clarification or add additional context in comments.

3 Comments

The only thing I find strange is that he's eager loading the HeroTypeNavigation to start the chain and it's lazy loading the other links along the chain. EF Core now requires you to declare your context with lazy loading enabled, so I don't know if that's the case here.
I would recommend avoiding passing back Entity classes to your view or calling your context straight from the controller (I know it's done, but it still makes me cringe)
Everyone has to start somewhere... :) Sadly with software development there are few good real-world examples that are "documented" and reflect best practices out in the wild.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.