Imagine a set of Entity Framework entities:
public class Country {
public string CountryCode { get; set; }
public string Name { get; set; }
public string Flag { get; set; }
}
public class Market {
public string CountryCode { get; set; }
public virtual Country Country { get; set; }
public int ProductID { get; set; }
public virtual Product Product { get; set; }
}
public class Product {
public int ProductID { get; set; }
public string Name { get; set; }
public virtual ICollection<Market> Markets{ get; set; }
}
Imagine as well a DOTNET 5 api GET
// GET api/product
[HttpGet]
public async Task<IActionResult> GetProduct([FromRoute] int id)
{
return Ok(await _context.Products
.Include(p => p.Markets)
.SingleAsync(m => m.ProductID == id));
}
If there are no markets attached to the entity the data returns without issue, but as soon as I have a few linked items attached I get an error:
HTTP Error 502.3 - Bad Gateway
The specified CGI application encountered an error and the server terminated the process.
I vaguely recall a previous application where every complex EF object had a "primitives only" type object to send and receive this object to and from the client, but I wonder if there is a way to communicate without intermediary objects?
eg:
public class ProductViewModel {
public int ProductID { get; set; }
public string Name { get; set; }
public List<MarketViewModel> Markets{ get; set; }
}
public class MarketViewModel {
public int ProductID { get; set; }
public Country Country { get; set; }
}
My concern is the coding overhead of translating every complex object back and forth from the client (which, I'll admit, I'm not sure is even a bad thing, maybe it has to be done anyways).
Since the scaffolded APIs seem to take and return entities directly I find myself wondering if there is a way to handle the complex part of the object directly
Edit #1:
Per Noel's comment below, if I change the code which is causing the error to
[HttpGet("{id}", Name = "GetProduct")]
public async Task<IActionResult> GetProduct([FromRoute] int id)
{
Product product = await _context.Products
.Include(t => t.Markets)
.SingleAsync(m => m.ProductID == id);
throw new System.Exception("error sample");
return Ok(product);
}
the stack trace is Correctly thrown. If I remove the exception, the 500 gateway error appears. I agree that it looks like it's probably a serialization error, but it's tough to say.
EDIT 2 - per a comment from Oleg below:
The solution to a bad gateway is to first explicitly update a more recent version of NewtonSoft.Json
in the dependencies in the project.json
file:
"dependencies": {
"Newtonsoft.Json": "8.0.1-beta3",
next you must alter the Startup.cs
file
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
with those two settings in place, the bad gateway no longer occurs and an api call successfully returns the complex object as expected.