在将OData添加到我的项目之前,我的路由设置如下:
config.Routes.MapHttpRoute( name: "ApiById", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }, constraints: new { id = @"^[0-9]+$" }, handler: sessionHandler ); config.Routes.MapHttpRoute( name: "ApiByAction", routeTemplate: "api/{controller}/{action}", defaults: new { action = "Get" }, constraints: null, handler: sessionHandler ); config.Routes.MapHttpRoute( name: "ApiByIdAction", routeTemplate: "api/{controller}/{id}/{action}", defaults: new { id = RouteParameter.Optional }, constraints: new { id = @"^[0-9]+$" }, handler: sessionHandler
所有控制器都提供Get,Put(操作名称为Create),Patch(操作名称为Update)和Delete.例如,客户端使用这些各种标准URL来表示CustomerType请求:
string getUrl = "api/CustomerType/{0}"; string findUrl = "api/CustomerType/Find?param={0}"; string createUrl = "api/CustomerType/Create"; string updateUrl = "api/CustomerType/Update"; string deleteUrl = "api/CustomerType/{0}/Delete";
然后我添加了一个OData控制器,其动作名称与我的其他Api控制器相同.我还添加了一条新路线:
ODataConfig odataConfig = new ODataConfig(); config.MapODataServiceRoute( routeName: "ODataRoute", routePrefix: null, model: odataConfig.GetEdmModel() );
到目前为止,我在客户端没有任何改变.当我发送请求时,我收到406 Not Available错误.
路线混乱了吗?我怎么解决这个问题?
如果您使用的是OData V4,请替换 using System.Web.Http.OData;
同 using System.Web.OData;
在ODataController为我工作.
将routePrefix设置为"api".
ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<CustomerType>("CustomerType"); config.MapODataServiceRoute(routeName: "ODataRoute", routePrefix: "api", model: builder.GetEdmModel());
你使用哪个OData版本?System.Web.OData
对于V3 ,检查OData V4使用的正确名称空间System.Web.Http.OData
.控制器中使用的命名空间必须与WebApiConfig中使用的命名空间一致.
另一件需要考虑的事情是URL区分大小写,因此:
localhost:xxx/api/Sites -> OK
localhost:xxx/api/sites -> HTTP 406
我遇到的问题是我已将我的实体集命名为“产品”,并且具有一个ProductController。原来,实体集的名称必须与您的控制器名称匹配。
所以
builder.EntitySet<Product>("Products");
使用名为ProductController的控制器将给出错误。
/ api /产品将给出406
/ api /产品将给出404
因此,使用某些新的C#6功能,我们可以改为:
builder.EntitySet<Product>(nameof(ProductsController).Replace("Controller", string.Empty));
配置路由的顺序具有影响.就我而言,我也有一些标准的MVC控制器和帮助页面.所以在Global.asax
:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(config => { ODataConfig.Register(config); //this has to be before WebApi WebApiConfig.Register(config); }); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); }
当我启动项目并且需要时,过滤器和routeTable部件不存在.
ODataConfig.cs
:
public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); //This has to be called before the following OData mapping, so also before WebApi mapping ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Site>("Sites"); //Moar! config.MapODataServiceRoute("ODataRoute", "api", builder.GetEdmModel()); }
WebApiConfig.cs
:
public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( //MapHTTPRoute for controllers inheriting ApiController name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); }
作为奖励,这是我的RouteConfig.cs
:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( //MapRoute for controllers inheriting from standard Controller name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }
这必须是那个确切的顺序.我尝试移动调用并最终导致MVC,Api或Odata因404或406错误而中断.
所以我可以打电话:
localhost:xxx/ - >导致帮助页面(家庭控制器,索引页面)
localhost:xxx/api/ - >导致OData $元数据
localhost:xxx/api/Sites - >导致我的SitesController的Get方法继承自ODataController
localhost:xxx/api/Test - >导致我继承自ApiController的TestController的Get方法.
我的问题与返回实体模型而不是我暴露的模型(builder.EntitySet<ProductModel>("Products");
)有关.解决方案是将实体映射到资源模型.