我正在研究在WebApi中使用odata。到目前为止这么好,我喜欢它比wcf数据服务更灵活。
但是,当我尝试在模型中使用虚拟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)/子项目
但是当我尝试做的时候 /的OData / MainItems(1)/子项(1)
我收到此错误 此服务不支持“〜/ entityset / key / navigation / key”
形式的OData请求我希望将此调用以及/ odata / MainItems(1)/ SubItems重定向到SubItemsController。
我可以通过制作自定义ODataPathHandler来做到这一点,但这不是正确的做法。
答案 0 :(得分:5)
没错。您不需要自定义路径处理程序。它表示我们理解的有效OData URL,可以将其解析为ODataPath
。您需要的是自定义路由约定。路由约定将ODataPath映射到控制器和操作。默认情况下,我们仅提供处理WCF DS客户端生成的URL的基本路由约定。看起来您正在使用我们没有路由约定的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)
。