【问题标题】:What is the proper way to scope OData methods to single controller?将 OData 方法范围限定为单个控制器的正确方法是什么?
【发布时间】:2017-09-11 20:45:13
【问题描述】:

我在同一个项目中让 WebApi 2 控制器与单个 OData 控制器并排工作。正在尝试设置所需的路由配置:

  • /api 的所有请求都应映射到此 ODataController
  • 所有其他请求都应定向到普通的 Web Api 控制器

当我尝试像这样将 /api 路由映射到 OData 控制器时:

class WebApiConfig
{
  public static void Register(HttpConfiguration configuration)
  {
    configuration.Routes.MapHttpRoute("API Default", "api/{action}/{id}",
        new { controller = "ApiOdata", id = RouteParameter.Optional });

    ODataModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Organization>("Organizations");
     configuration.Routes.MapODataServiceRoute(
        routeName: "ODataRoute",
        routePrefix: "Api",
        model: builder.GetEdmModel());
   }
}

所有方法调用对 Web Api 和 OData 控制器都可以正常工作,但像 /api/$metadata 这样的请求不起作用。

当我删除“API 默认”路由时 - 对 /api/Organizations 等 OData 控制器方法的请求停止工作(返回 404)但 /api/$metadata 开始.

详细的404错误信息:

<Error>
 <Message>
  No HTTP resource was found that matches the request URI 'http://localhost:53576/api/Organizations'.
 </Message>
 <MessageDetail>
   No type was found that matches the controller named 'Organizations'.
 </MessageDetail>
</Error>

将所有 OData 调用映射到单个控制器操作的正确方法是什么?

【问题讨论】:

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


    【解决方案1】:

    终于有了自定义路由约定。为其添加类:

    public class CustomControllerRoutingConvention : IODataRoutingConvention
    {
        public string SelectAction(System.Web.OData.Routing.ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
        {
            if (odataPath.PathTemplate.StartsWith("~/entityset") 
                || odataPath.PathTemplate.StartsWith("~/unboundfunction"))
            {
                return odataPath.Segments[0].Identifier;
            }
            // Not a match.
            return null;    
        }
    
        public string SelectController(System.Web.OData.Routing.ODataPath odataPath, HttpRequestMessage request)
        {
            if (!odataPath.PathTemplate.Contains("$metadata"))
            {
                if (odataPath.PathTemplate != "~")
                {
                    return "ApiOdata";
                }
            }
            return null;
        }
    }
    

    并在WebApiConfig.cs的Register方法中使用:

    public static void Register(HttpConfiguration configuration)
    {
      ...
      IList<IODataRoutingConvention> routingConventions =  ODataRoutingConventions.CreateDefault();
        routingConventions.Insert(0, new CustomControllerRoutingConvention());
    
        configuration.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: "Api",
            pathHandler: new DefaultODataPathHandler(),
            routingConventions: routingConventions,
            model: builder.GetEdmModel());
    }
    

    这不是完美的解决方案,并且不能为每个 OData 请求提供服务(只有元数据、实体集和未绑定的函数,如“api/Organizations”),但它足以与 o.js 和 Simple.Odata.Client 等客户端一起工作。 此外,它还可以避免我的项目的控制器混乱和臃肿。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-23
      相关资源
      最近更新 更多