2013-03-29 31 views
4

我正在研究在WebApi中使用odata。到目前为止这么好,我喜欢那种更加灵活的wcf数据服务。WebApi OData实体集/键/导航/键支持

但是,当我尝试在模型中使用虚拟IQueryable属性时遇到问题。

因此,例如,我有这些模型类:

public class MainItem 
{ 
    public int Id { get; set;} 
    public virtual IEnumerable<SubItem> SubItems { get; set;} 
} 

而且我MainItemsController看起来像这样

public class MainItemsController : EntitySetController<MainItem, int> 
{ 
    [Queryable] 
    public override IQueryable<MainItem> Get() 
    { 
     return SomeMainItemIQueryable(); 
    } 

    public override GetEntityByKey(int key) 
    { 
     return SingleMainItem(key); 
    } 

    [Queryable] 
    public IQueryable GetSubItems(int key) 
    { 
     return SomeSubItemIQueryable(SingleMainItem(key)); 
    } 
} 

我得到以下网址的正确的结果: /的OData/MainItems /OData的/ MainItems(1) /odata/MainItems(1)/ SubItems

但是,当我尝试做 /的OData/MainItems(1)/子项(1)

我得到这个错误 此服务不支持的格式 '〜/ EntitySet的/键/导航/键'

我会的OData请求喜欢将此调用重定向到/ odata/MainItems(1)/ SubItems到SubItemsController。

我可以通过制作一个自定义的ODataPathHandler来做到这一点,但是这并不像这样做的正确方式。

回答

5

没错。你不需要一个自定义的路径处理程序。它代表我们了解的有效OData网址,并可将其解析为ODataPath。你需要的是一个自定义路由约定。路由约定将ODataPath映射到控制器和操作。默认情况下,我们只提供处理WCF DS客户端生成的URL的基本路由约定。看起来您正在使用我们没有路由约定的网址。尽管写一个很简单。例如,

public class ContainmentRoutingConvention : IODataRoutingConvention 
{ 
    public string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap) 
    { 
     IEdmEntitySet entitySet = odataPath.EntitySet; 

     if (odataPath.PathTemplate == "~/entityset/key/navigation") 
     { 
      controllerContext.RouteData.Values["key"] = (odataPath.Segments[1] as KeyValuePathSegment).Value; 
      return "Get" + entitySet.Name; 
     } 
     else if (odataPath.PathTemplate == "~/entityset/key/navigation/key") 
     { 
      controllerContext.RouteData.Values["key1"] = (odataPath.Segments[1] as KeyValuePathSegment).Value; 
      controllerContext.RouteData.Values["key2"] = (odataPath.Segments[3] as KeyValuePathSegment).Value; 
      return "Get" + entitySet.ElementType.Name; 
     } 

     return null; 
    } 

    public string SelectController(ODataPath odataPath, HttpRequestMessage request) 
    { 
     if (odataPath.PathTemplate == "~/entityset/key/navigation" || 
      odataPath.PathTemplate == "~/entityset/key/navigation/key") 
     { 
      IEdmNavigationProperty navigationProperty = (odataPath.Segments[2] as NavigationPathSegment).NavigationProperty; 
      IEdmEntitySet entitySet = odataPath.EntitySet; // the target entity set, which would be 'SubItems'; 

      return entitySet.Name; 
     } 

     return null; 
    } 
} 

这只会处理您提到的两个网址。应该很容易扩展以支持其他网址。

处理〜/ entityset/key/navigation的操作的签名将为IEnumerable<Order> GetOrders(int key),url〜/ entityset/key/navigation/key将为Order GetOrder(int key1, int key2)

+0

非常感谢! – Rolfvm