Question

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");
Était-ce utile?

La solution

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.

Autres conseils

According to the OData specification /api/Nodes return all entities of type Node. So, /api/Nodes(234) will return node #234. You need to develope a custom method to return the root nodes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top