带有可选参数的 OData 路由
OData Routing with Optional Parameter
我有一个 OData (v3) Web API 2 项目,它是另一个 wcf Web 服务的包装器。此 odata 连接的预期客户端是 SharePoint 2013。我正在此包装器中创建 CRUD 操作,并注意到当要求 sharepoint 删除某些内容时,它会以这种格式发送请求:/Entity(Identity=XX) 而不是正常的 /Entity (XX) 我已经正常工作了。我需要能够在不破坏另一个请求的情况下处理该请求。这是我的代码:
public IHttpActionResult GetSchool([FromODataUri] int key, ODataQueryOptions<School> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
SchoolDataSource data = new SchoolDataSource();
var result = data.GetByID(key);
return Ok<School>(result);
//return StatusCode(HttpStatusCode.NotImplemented);
}
这适用于 /Schools(1) 的请求,但不适用于 /Schools(ID=1)。我试过添加:
[Route("Schools(ID={key}")]
这使得 /Schools(ID=1) 路由有效,但几乎破坏了其他一切(406 错误)。我尝试添加上述属性和
[Route("Schools({key})")]
看看我是否能让它们都工作,但它也不能正常工作。我对此很陌生,希望至少能得到一些指导。这是我的 WebApiConfig:
config.MapHttpAttributeRoutes();
config.EnableQuerySupport();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
// Web API configuration and services
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<School>("Schools");
builder.DataServiceVersion = new Version("2.0");
config.Routes.MapODataRoute("odata", null, builder.GetEdmModel());
// Web API routes
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
我得到的错误:
406 如果我设置了路由属性。 500 如果我没有设置路由属性。似乎我的服务不知道如何处理参数,除非我指定它,但如果我这样做,所有调用都会出现 406 错误。
可能不是最好的方法,但它适用于此 class:
public class SharePointRoutingConvention : EntitySetRoutingConvention
{
public override string SelectAction(ODataPath odataPath, HttpControllerContext context,
ILookup<string, HttpActionDescriptor> actionMap)
{
//Gets the entity type
IEdmEntityType entityType = odataPath.EdmType as IEdmEntityType;
//makes sure the format is correct
if (odataPath.PathTemplate == "~/entityset/key")
{
//parses out the path segment (Identity=X)
KeyValuePathSegment segment = odataPath.Segments[1] as KeyValuePathSegment;
//Gets the verb from the request header
string actionName = context.Request.Method.ToString();
// Add keys to route data, so they will bind to action parameters.
KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
//Checks to see if the "Identity=" part is in the url
if (keyValueSegment.Value.Contains("Identity="))
{
//removes the extra text
context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value.Replace("Identity=", "");
}
else
{
//parses it normally
context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;
}
//returns the verb
return actionName;
}
// Not a match.
return null;
}
}
并对 webapiconfig 进行更改:
var conventions = ODataRoutingConventions.CreateDefault();
//adding the custom odata routing convention
conventions.Insert(0, new SharePointRoutingConvention());
config.Routes.MapODataRoute(
routeName: "odata",
routePrefix: null,//this is so that you can type the base url and get metadata back (http://localhost/)
model: builder.GetEdmModel(),
pathHandler: new DefaultODataPathHandler(),
routingConventions: conventions //this assigns the conventions to the route
);
我有一个 OData (v3) Web API 2 项目,它是另一个 wcf Web 服务的包装器。此 odata 连接的预期客户端是 SharePoint 2013。我正在此包装器中创建 CRUD 操作,并注意到当要求 sharepoint 删除某些内容时,它会以这种格式发送请求:/Entity(Identity=XX) 而不是正常的 /Entity (XX) 我已经正常工作了。我需要能够在不破坏另一个请求的情况下处理该请求。这是我的代码:
public IHttpActionResult GetSchool([FromODataUri] int key, ODataQueryOptions<School> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
SchoolDataSource data = new SchoolDataSource();
var result = data.GetByID(key);
return Ok<School>(result);
//return StatusCode(HttpStatusCode.NotImplemented);
}
这适用于 /Schools(1) 的请求,但不适用于 /Schools(ID=1)。我试过添加:
[Route("Schools(ID={key}")]
这使得 /Schools(ID=1) 路由有效,但几乎破坏了其他一切(406 错误)。我尝试添加上述属性和
[Route("Schools({key})")]
看看我是否能让它们都工作,但它也不能正常工作。我对此很陌生,希望至少能得到一些指导。这是我的 WebApiConfig:
config.MapHttpAttributeRoutes();
config.EnableQuerySupport();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
// Web API configuration and services
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<School>("Schools");
builder.DataServiceVersion = new Version("2.0");
config.Routes.MapODataRoute("odata", null, builder.GetEdmModel());
// Web API routes
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
我得到的错误: 406 如果我设置了路由属性。 500 如果我没有设置路由属性。似乎我的服务不知道如何处理参数,除非我指定它,但如果我这样做,所有调用都会出现 406 错误。
可能不是最好的方法,但它适用于此 class:
public class SharePointRoutingConvention : EntitySetRoutingConvention
{
public override string SelectAction(ODataPath odataPath, HttpControllerContext context,
ILookup<string, HttpActionDescriptor> actionMap)
{
//Gets the entity type
IEdmEntityType entityType = odataPath.EdmType as IEdmEntityType;
//makes sure the format is correct
if (odataPath.PathTemplate == "~/entityset/key")
{
//parses out the path segment (Identity=X)
KeyValuePathSegment segment = odataPath.Segments[1] as KeyValuePathSegment;
//Gets the verb from the request header
string actionName = context.Request.Method.ToString();
// Add keys to route data, so they will bind to action parameters.
KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
//Checks to see if the "Identity=" part is in the url
if (keyValueSegment.Value.Contains("Identity="))
{
//removes the extra text
context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value.Replace("Identity=", "");
}
else
{
//parses it normally
context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;
}
//returns the verb
return actionName;
}
// Not a match.
return null;
}
}
并对 webapiconfig 进行更改:
var conventions = ODataRoutingConventions.CreateDefault();
//adding the custom odata routing convention
conventions.Insert(0, new SharePointRoutingConvention());
config.Routes.MapODataRoute(
routeName: "odata",
routePrefix: null,//this is so that you can type the base url and get metadata back (http://localhost/)
model: builder.GetEdmModel(),
pathHandler: new DefaultODataPathHandler(),
routingConventions: conventions //this assigns the conventions to the route
);