1

This is an excerpt from a straightforward API controller:

[Route("api/cities")]
public class CitiesController : BaseController
{
    internal protected ICityRepository _cityRepository;
    public CitiesController(ICityRepository cityRepository) : base()
    {
        _cityRepository = cityRepository;
    }

    // GET: api/Cities
    [HttpGet]
    public IEnumerable<City> Get()
    {
        var cities = _cityRepository.GetAll();
        return cities;
    }

    // GET: api/Cities/5
    [HttpGet("{id}", Name = "GetCity")]
    public IActionResult Get(Guid id)
    {
        City city = _cityRepository.Get(id);
        if (city == null)
        {
            return NotFound();
        }

        return new ObjectResult(city);
    }

BaseController does nothing more than inherit from Controller at the moment. Whenever I call api/cities or api/cities/E4477C67-894E-492C-95DE-001DC73730A1 I get something like this in return:

{
    "$id": "2828",
    "$values": [
    {
        "$id": "2829"
    },
    {
        "$id": "2830"
    },
    {
        "$id": "2831"
    },
    ...

and

{
    "$id": "2827"
}

respectively. It looks like it's returning a sequence number of a serialized object or something. After some Googling I came across the JsonObject attribute which, by adding it to my base class, made the objects get serialized in some sort of fashion. Mind the "some sort of fashion".

The response for a basic get looks a bit like this:

{
"$id": "2",
"$values": [
    {
        "$id": "3",
        "name": "Beigem",
        "zipCode": "1852",
        "id": "e4477c67-894e-492c-95de-001dc73730a1",
        "concurrencyStamp": "AAAAAAAAZxE=",
        "created": "2017-11-06T08:22:19.9733333",
        "createdBy": null,
        "modified": "2017-11-06T08:22:19.9733333",
        "modifiedBy": null,
        "isNew": false,
        "__Key": "e4477c67-894e-492c-95de-001dc73730a1"
    },
    ...

Still with the $id and $values things. I don't want that. I want it to be a clean json result, not the pear-shaped one like this.

  1. Why do I need to add the JsonObject attribute? I don't see it in any other example.
  2. What's up with the weird formatting. I cannot find any reference to that either...
TylerH
  • 20,799
  • 66
  • 75
  • 101
Sylvain Girard
  • 368
  • 3
  • 13
  • 1
    That's the newtonsoft format for preserving object references. See https://www.newtonsoft.com/json/help/html/PreserveObjectReferences.htm – dbc Nov 10 '17 at 07:44

1 Answers1

3

As a rule you should not serialize EF entities.

Consider defining data contracts for your controllers and return only data that is required by design of API call. With such approach you'll get EF entity from your repository and copy relevant fields to output data object:

// GET: api/Cities/5
[HttpGet("{id}", Name = "GetCity")]
public IActionResult Get(Guid id)
{
    City city = _cityRepository.Get(id);
    if (city == null)
    {
        return NotFound();
    }

    CityData cityData = new CityData
    {
        Name = city.Name,
        ...
    };

    return Json(cityData);
}
CodeFuller
  • 30,317
  • 3
  • 63
  • 79
  • Ok, adding a viewmodel in between solved it! The cause, however, appeared to be something else since a viewmodel is just an object, as my entities are supposed to be. Looking deeper into the entity structure I discovered a rogue DataContractAttribute on a base class for my entities. Removing this also makes the entities themselves serialize properly. Granted, a viewmodel should always be used but that wasn't the solution. – Sylvain Girard Nov 10 '17 at 09:30