asp.net-coreodataodata-v4asp.net-core-odata

ASP.NET Core OData 8: allow deep navigation


We're using odata2ts as our client side library. As stated on it's docs:

OData exposes and advertises entry points, most often entity sets (e.g. /People). We can traverse to a specific entity of that collection by its key(s) (e.g. /People('russelwhyte')) and use its navigation properties to traverse ever deeper into the service (e.g. /People('russelwhyte')/BestFriend/Trips). There is no defined end to this kind of navigation.

So given the following EF classes (generated by EF Core Power Tools, SQL Server 2012 - database-first approach), registered as entity sets with pluralized names on the EDM

public class Service
{
    int ServiceId { get; set; }
    ICollection<ServiceArticle> ServiceArticle { get; set; }
}

public class ServiceArticle
{
    int ServiceArticleId { get; set; }

    int ServiceId { get; set; }
    Service Service { get; set; }
    int ArticleId { get; set; }
    Article Article { get; set; }
}    

public class Article
{
    int ArticleId { get; set; }
}

Although it doesn't seem too useful, the odata2ts service allows to call

var article = await odata2tsService.Services(15).ArticleService(20).Article().query();

which translates to the request

/Services(15)/ArticleService(20)/Article

as you'd expect.

Now the question is, how do we allow this from an API standpoint?

We've got endpoints like the following convention to get each of an EntityType properties, so there's

ServicesController.cs:

[HttpGet]
[EnableQuery]
public IActionResult GetArticleService([FromRoute] int key)

and Get() and Get([FromRoute] int key) for each of the involved entities on their respective controllers. What are we missing to achieve desired result? Given Sam Xu comment here it would seem that this is covered by convention, but we haven't been able to get this to work by adding a:

[HttpGet]
[EnableQuery]
public IActionResult GetArticleFromService([FromRoute] int key, [FromRoute] int relatedKey)

Solution

  • It seems you want to get a convention as:

    ~/{entityset}({key})/{navigationProperty}({key})

    In the convention, it seems no such convention built by default.

    You can build the convention by yourself using any ways, or use the attribute routing to achieve the goal.

    I create a sample for your reference at here. Please leave any comments in the repo by creating issues and love to see any contributions by pull request.