WebAPI OData和自定义导航链接

时间:2013-07-23 09:47:36

标签: asp.net asp.net-web-api odata

我正在构建基于WebAPI的OData服务,我遇到导航链接问题。基本上我有两个类,其中一个引用另一个。当我请求原子或详细的JSON时,我可以看到我在两者之间有一个链接。但是,我想自定义uri,使其指向不同的位置,而不是OData库假定的默认位置。

使用一个简单的例子,假设我有两个名为'entity1'和'entity2'的实体集。它们作为OData服务公开,分别位于:/ api / entities1和/ api / entities2。

这是我的示例模型代码:

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; }
}

我正在使用ODataConventionModelBuilder注册如下:

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);

我已将控制器实现为EntitySetController。所有这些都按预期工作,当我请求详细的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"
    }]
  }
}

我想要做的是让Entity1实例中的'OtherEntity'字段引用/ api / entities2下的关联Entity2实例,以便链接看起来像/ api / entities2(2)(假设Entity2实例的ID为“2”。

我知道我可以将'OtherEntity'的类型设为Uri并在我的控制器中插入适当的值,但这看起来有点像黑客(但我可能是错的)。根据对OData的理解,我认为正确的方法是修改导航属性,但我不确定如何或在哪里。

感谢任何帮助。提前谢谢。

干杯,  史蒂夫

1 个答案:

答案 0 :(得分:2)

您可以执行以下操作:

        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);