I have a wcf data service that has a service "Nodes" that return the following entity.
[DataServiceKey("NodeId")]
public class Node
{
public int NodeId { get; set; }
public IQueryable<Node> SubNodes
{
get { return new NodeRepository().GetNodes(this.NodeId); }
}
}
which gives me a fully recursive OData service. I get all root nodes with http://www.test.com/api/Nodes, a single node with http://www.test.com/api/Nodes(123), it's subnodes with http://www.test.com/api/Nodes(123)/SubNodes, a single subnode with http://www.test.com/api/Nodes(123)/SubNodes(234), the subnode's subnodes with http://www.test.com/api/Nodes(123)/SubNodes(234)/SubNodes and so on.
The question is how to consume this data in code.
I can use
var context = new MyServiceV1.TheServiceContext(new Uri(dataUrl));
var nodes = context.Nodes;
to get the first level of nodes. Then if I pass the context and my nodes to this method I can get the subnodes of the first level nodes.
private void RecurseNodes(TheServiceContext context, IEnumerable<Node> nodes)
{
foreach (var node in nodes)
{
var subNodes = dataContext.LoadProperty(node, "SubNodes") as QueryOperationResponse<Node>;
RecurseNodes(dataContext, subNodes);
}
}
The above LoadProperty call will generate the correct url (/api/Nodes(123)/SubNodes) but when it tries to load the subnodes of the next level (i.e. the node with id 234) it uses the url /api/Nodes(234)/SubNodes. What it should use is /api/Nodes(123)/SubNodes(234)/SubNodes.
Do I have to start generating the urls myself or can I instruct the datacontext to accomplish this?
SOLUTION: The problem is in the OData-feed, since /api/Nodes does not return all Node's, only the root nodes. This is how I solved it without touching the OData-feed:
private void RecurseNodes(IEnumerable<Node> nodes, NCContentServiceContext dataContext, string baseUrl)
{
foreach (var node in nodes)
{
var url = baseUrl + "(" + node.NodeId + ")/SubNodes";
var subNodes = dataContext.Execute<Node>(new Uri(url, UriKind.Relative)).ToList();
RecurseNodes(subNodes, dataContext, url);
}
}
and the caller is
var context = new MyServiceV1.TheServiceContext(new Uri(dataUrl));
RecurseNodes(context.Nodes, context, "/Nodes");
I'm not sure why you need the recursive URI, but the URL here generated by LoadProperty() is correct from an OData perspective.
In OData world, every entity has a unique entity id. For instance, /api/Nodes(123)
and /api/Nodes(234)
are the entity ids of the two entities. So the query /api/Nodes(123)/SubNodes(234)
is really reaching for the entity /api/Nodes(234)
. And when you ask for /api/Nodes(123)/SubNodes(234)/SubNodes
, it's the same as /api/Nodes(234)/SubNodes
. So LoadProperty is doing the right thing here.
If you still need to build the recursive URI, you'll have to build it yourself.