0
votes

I'm working on building a WebAPI based OData service and I’m having issues with navigation links. Basically I have two classes where one has a reference to another. When I request either atom or verbose JSON I can see that I have a link between the two. However, I’d like to customize the uri to have it point to a different location rather than the default assumed by the OData library.

Using a simple example, assume that I have two entity sets called ‘entity1’ and ‘entity2’. These are exposed as OData services located at: /api/entities1 and /api/entities2 respectively.

Here’s my sample model code:

public class Entity1 {
  public int ID { get; set; }
  public string Name { get; set; }
  public virtual Entity2 OtherEntity { get; set; }
}

public class Entity2 {
  public int ID { get; set; }
  public string Value { get; set; }
}

I’m using the ODataConventionModelBuilder to register these as follows:

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entity1>("entities1");
builder.EntitySet<Entity2>("entities2");
IEdmModel model = builder.GetEdmModel();
config.Routes.MapODataRoute(routeName: "OData", routePrefix: "api", model: model);

I've implemented the controller as an EntitySetController. All of this works as expected and I get the following response when I request verbose JSON:

{
  "d": {
    "results": [{
      "__metadata": {
        "id": "http://localhost:37826/api/entities1(1)",
        "uri": "http://localhost:37826/api/entities1(1)",
        "type": "ODataSample.Models.Entity1"
      },
    "OtherEntity": {
        "__deferred": {
          "uri": "http://localhost:37826/api/entities1(1)/OtherEntity"
        }
      },
      "ID": 1,
      "Name": "First Entity"
    }]
  }
}

What I’d like to do is to have the ‘OtherEntity’ field in an Entity1 instance refer to the associated Entity2 instance under /api/entities2 so that the link appears something like /api/entities2(2) (assuming the ID of the Entity2 instance is '2').

I know that I could just make the type of ‘OtherEntity’ a Uri and insert the appropriate value in my controller but that seems a bit of a hack (but I could be wrong). From what understand about OData, I believe the right way to do this is to modify the navigation property but I’m not sure how or where.

Any help is appreciated. Thanks in advance.

Cheers, Steve

1

1 Answers

2
votes

You could do something like the following:

        var entities1 = builder.EntitySet<Entity1>("Entities1");
        entities1.HasNavigationPropertyLink(entities1.EntityType.NavigationProperties.First(np => np.Name == "OtherEntity"),
            (context, navigation) =>
            {
                return new Uri(context.Url.ODataLink(new EntitySetPathSegment("Entities2"), new KeyValuePathSegment(context.EntityInstance.OtherEntity.Id.ToString())));
            }, followsConventions: false);