Reputation: 827
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?
Upvotes: 3
Views: 929
Reputation: 2479
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;
});
Upvotes: 9