0

I added this line to resolve circular errors in my JSON:

        services.AddMvc()
                .AddJsonOptions(
                    options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                );

But now, I find that some of my controllers return too much information.

I found this similiar question, but reading through it, I couldn't really figure out how to apply it to my code: Avoiding Circular referencing providing too much data

For example, this simple controller returns data that I don't want:

    [HttpGet("{id}")]
    public async Task<ActionResult<BookList>> GetBookList(string id)
    {
        var bookList = await _context.BookList.FindAsync(id);

        return bookList;
    }   

Here is the model for that data:

public partial class BookList
{
    public BookList()
    {
        BookLinks = new HashSet<BookLinks>();
    }

    public string BookId { get; set; }
    public Guid LibraryId { get; set; }
    public string BookTitle { get; set; }
    public string BookText { get; set; }
    public byte? BookType { get; set; }

    public virtual LibraryList Library { get; set; }
    public virtual ICollection<BookLinks> BookLinks { get; set; }
}

}

So when I hit the controller above, I am getting all the unwanted data for BookLinks in addition to the data from BookList.

I just want the data from BookList based on a particular BookId.

I was under the impression, that if I wanted all data returned(including the BookLinks data), I'd have to do something like this:

        var bookList = await _context.BookList
            .Include(i => i.BookLinks)
            .Where(b => b.BookId == id)
            .ToListAsync();         

That said, is there way to limit or exclude data that I don't want?

Thanks!

1 Answer 1

1

Your navigation props are virtual, so I'm assuming you have lazy-loading enabled. When the serializer walks the object, it will trigger the get for each of these properties, which will in turn issue queries one by one to backfill the data, which will then get serialized as well. Assuming that it doesn't encounter a circular reference, it will continue to walk down the related entities, loading and serializing each relationship.

This is a perfect illustration of why you should never serialize entities. Entities are for working with the database. They are not for and should not be used for returning responses, rendering views, etc.

Instead, create a view model/DTO/whatever you want to call it. Map your entity class(es) on to that, and then return the view model instead. That way, you can control exactly what the response is.

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

7 Comments

Thanks! Yes I do have lazy loading. So the model BookList is a table from my database and Visual Studio added all the code for my model and database context class when I created the project. But what you are saying, is that I shouldn't directly use BookList. I should make another class, lets call it Books, and then have the controller use that? Is this what you are referring to? ardalis.com/…
Yes, essentially. Create a class with just the properties you do want to return. If there's relationships, create separate classes for each of those with just the properties you want to return, and then all these classes only reference other view models/DTOs. No entity class should be present anywhere in the hierarchy. Map your entity object graph on to the view model versions, and return the view model versions.
This comes from the school of hard knocks. The docs are intentionally simplistic. They're trying to teach you the basic concepts. If they threw in the higher level stuff, it would obscure that. They are getting better at providing links to further/more extensive information, though.
Also, this isn't strictly an EF thing. It's a domain model vs view model thing, i.e. it's objected oriented design patterns, in general. Your API is a form of an anti-corruption layer, and as such should serve as bridge between your domain and the outside.
Yep. That's it.
|

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.