Reputation: 4481
I have a few composed object being returned on a WebApi Restful service (for simplicity):
class Item {
List<Category> Categories { get; set; }
object Value { get; set; }
}
class Category {
List<Item> ItemsInCategory { get; set; }
}
These values are being served by a simple ApiController:
publicHttpResponseMessage getItems()
{
List<Category> categories;
...
return Request.CreateResponse(HttpStatusCode.OK, new { results = items});
}
The problem: Say Item(A) is in Category(A) this will result a circular dependency which will "stuck" the serialization. Therefore the webapi team (which is the last time I am using as a backend B.T.W) has exposed reference loop handling: (WebApiConfig.cs)
JsonMediaTypeFormatter jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
var jSettings = new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
};
jsonFormatter.SerializerSettings = jSettings;
That said it doesn't really work.
Nor the "MaxDepth" property.
I've searched many ways and couldn't find a built-in way to achieve this (there are many "hacking") that achieve some variations of JsonConverter (and also [JsonIgnore]) that help achieve some proportions of this.
This is a VERY common request to control the depth of the response, isn't it?
Any chance Microsoft has completely ignored this issue and there is no built in way to deal with this issue????
Upvotes: 1
Views: 1317
Reputation: 532435
I think the fundamental problem is that your API is attempting to do too much in one call. I'd probably split it up into /api/categories
, /api/categories/{id}
, /api/category/{id}/items
, /api/items/{id
}. The first url would only return category information, the second detail information about the category, the third information on the items in that category, and the fourth the detail information on an item. You would flatten out the models in the API so that you're not representing recursive data, instead you'd include the URL to retrieve the information on a category that an item belongs to when you get the item's details.
For example, /api/items/foo
would return something like:
{
"name" : "foo",
"value" : "bar",
"categories" [
{
"name" : "Cat A",
"parent" : {
"name" : "Top Cat A",
"location" : "/api/categories/topcata"
}
"location" : "/api/categories/cata"
},
{
"name" : "Cat B",
"parent" : null,
"location" : "/api/categories/catb"
}
]
}
This turns the serialization problem into a model mapping problem which you have much more control over. I think it also provides a much cleaner, more manageable API for your consumers to use.
Upvotes: 2