3

I'm running into a problem setting up a simple many-to-many relationship in Entity Framework Core and Asp .NET Core and it's driving me crazy. Whenever I try to return a related collection with the Includes() method, my HTTP response breaks. Could anybody help me out?

Quick demonstration, here's a simple relationship between Product and Category classes:

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public ICollection<ProductCategory> ProductCategories { get; set; }
}

public class Category
{
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public ICollection<ProductCategory> ProductCategories { get; set; }
}

public class ProductCategory
{
    public int ProductId { get; set; }
    public int CategoryId { get; set; }
    public Product Product { get; set; }
    public Category Category { get; set; }
}

And the Entity Framework DbContext:

public class ProductDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<ProductCategory> ProductCategories { get; set; }

    public ProductDbContext(DbContextOptions<ProductDbContext> options) : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ProductCategory>().HasKey(s => new { s.ProductId, s.CategoryId });

        base.OnModelCreating(modelBuilder);
    }
}

And a controller with a Set method (just a fast way of seeding data) and a Get method to actually get the results:

public class ProductController : Controller
{
    ProductDbContext _context;

    public ProductController(ProductDbContext context)
    {
        _context = context;
    }

    public IActionResult Set()
    {
        _context.Products.AddRange(
            new Product
            {
                Name = "TestProduct1"
            },
            new Product
            {
                Name = "TestProduct2"
            }
            );

        _context.Categories.AddRange(
            new Category
            {
                Name = "TestCategory1"
            },
            new Category
            {
                Name = "TestCategory2"
            }
            );

        _context.SaveChanges();

        _context.ProductCategories.AddRange(
            new ProductCategory
            {
                ProductId = 1,
                CategoryId = 1
            },
            new ProductCategory
            {
                ProductId = 2,
                CategoryId = 1
            },
            new ProductCategory
            {
                ProductId = 2,
                CategoryId = 2
            }
            );

        _context.SaveChanges();

        return Ok();
    }

    public IActionResult Get()
    {
        var products = _context.Products
            //.Include(p => p.ProductCategories)
            .ToList();
        return Ok(products);
    }
}

To test, first I hit the Set method through Postman (http://localhost:54551/product/set). After this, hitting the Get method (http://localhost:54551/product/get) returns this:

[
    {
        "productId": 1,
        "name": "TestProduct1",
        "productCategories": null
    },
    {
        "productId": 2,
        "name": "TestProduct2",
        "productCategories": null
    }
]

However, uncommenting the call to Includes in the Get method gives me this:

Could not get any response

There was an error connecting to http://localhost:54551/product/get.
Why this might have happened:
The server couldn't send a response:
Ensure that the backend is working properly
Self-signed SSL certificates are being blocked:
Fix this by turning off 'SSL certificate verification' in Settings > General
Proxy configured incorrectly
Ensure that proxy is configured correctly in Settings > Proxy
Request timeout:
Change request timeout in Settings > General

What's the piece that I'm missing? I have CORS set up to allow any origin. If I set a breakpoint on return Ok(products) with the Includes() call uncommented, I can see that the data is being added to the products object.

Why would the response fail?

2
  • 1
    I imagine the response is failing as your code is throwing an exception. Try debugging to see what's happening. Commented Feb 10, 2018 at 21:11
  • Probably you have circular reference. (Product -> Product Category -> Product) Commented Feb 10, 2018 at 22:49

1 Answer 1

9

This is a circular reference problem for the json serializer. You can fix that by adding in the Startup.cs file the following config:

services.AddMvc()
    .AddJsonOptions(option =>
    {
        option.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    });
Sign up to request clarification or add additional context in comments.

3 Comments

Exactly what I was missing. Thank you so much!
god that problem cost me 2 hours
thank you very much for this hint. i knew there was a part of the configuration missing in order to get it to work ;-)

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.