OData 路由异常
OData route exception
我是新手,所以我将从代码开始,然后再进行解释。
问题是这个
[HttpGet, ODataRoute("({key})")]
public SingleResult<Employee> GetByKey([FromODataUri] string key)
{
var result = EmployeesHolder.Employees.Where(id => id.Name == key).AsQueryable();
return SingleResult<Employee>.Create<Employee>(result);
}
[HttpGet, ODataRoute("({key})")]
public SingleResult<Employee> Get([FromODataUri] int key)
{
var result = EmployeesHolder.Employees.Where(id => id.Id == key).AsQueryable();
return SingleResult<Employee>.Create<Employee>(result);
}
我有这 2 个操作,但其中一个我想按字符串搜索,另一个我想按数字搜索(尽管这不是问题所在)。如果我这样离开它,它将适用于 (int) 情况,但对于字符串 "....odata/Employees('someName')" 我会得到一个:HTTP 404(这是正常的)但是如果我尝试更具体地使用采用字符串
的方法
webApiConfig 中的代码。
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees");
builder.Function("GetByKeyFromConfig").Returns<SingleResult<Employee>>().Parameter<string>("Key");
控制器中的代码
[ODataRoutePrefix("Employees")]
public class FooController : ODataController
{
[HttpGet, ODataRoute("GetByKeyFromConfig(Key={key})")]
public SingleResult<Employee> GetByKey([FromODataUri] string key)
{ ... }
}
我得到了一个期望
{"The complex type
'System.Web.Http.SingleResult`1[[OData_Path.Employee, OData_Path,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' refers to the
entity type 'OData_Path.Employee' through the property 'Queryable'."}
如果我在 WebApiConfig
中更改方法的 return 类型
builder.Function("GetByKeyFromConfig").Returns<Employee>().Parameter<string>("Key");
我明白了,我不知道为什么。
{"The path template 'Employees/GetByKeyFromConfig(Key={key})' on the
action 'GetByKey' in controller 'Foo' is not a valid OData path
template. The request URI is not valid. Since the segment 'Employees'
refers to a collection, this must be the last segment in the request
URI or it must be followed by an function or action that can be bound
to it otherwise all intermediate segments must refer to a single
resource."}
我已经搜索并试图获得解释,但每次我找到答案都不起作用。我挣扎了好几天。
根据 2 个答案更新后
still have the Invalid OData path template exception
WebApiConfig 代码
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees").EntityType.HasKey(p => p.Name);
var employeeType = builder.EntityType<Employee>();
employeeType.Collection.Function("GetByKey").Returns<Employee>().Parameter<int>("Key");
config.EnableUnqualifiedNameCall(unqualifiedNameCall: true);
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
控制器代码
[EnableQuery, HttpGet, ODataRoute("Employees/GetByKey(Key={Key})")]
public SingleResult<Employee> GetByKey([FromODataUri] int Key)
{
var single = Employees.Where(n => n.Id == Key).AsQueryable();
return SingleResult<Employee>.Create<Employee>(single);
}
我也尝试过使用特定的命名空间
builder.Namespace = "NamespaceX";
[EnableQuery, HttpGet, ODataRoute("Employees/NamespaceX.GetByKey(Key={Key})")]
和
[EnableQuery, HttpGet, ODataRoute("Employees/NamespaceX.GetByKey")]
这篇关于 OData/Webapi 功能支持的文档对您有帮助吗? http://odata.github.io/WebApi/#04-06-function-parameter-support你的第二种方法有问题。
你是用 Employees/GetByKeyFromConfig(Key={key}) 调用的,所以你应该像这样声明函数:
builder.EntityType<Employee>().Collection.Function("GetByKeyFromConfig")
你应该用命名空间调用,比如Employees/yournamespace.GetByKeyFromConfig
第一个场景可以使用这个功能吗? http://odata.github.io/WebApi/#04-17-Alternate-Key
希望对您有所帮助,谢谢。
Update
:
Function declaration is right now, the error message showed because your ODataRoute
is wrong, remove your ODataRoute, 该函数可以调用为 Employees/Default.GetByKey(1)
, WebAPI/OData 可以默认路由到此函数.
或者给ODataRoute添加命名空间,默认是Default
,改成builder.Namespace
不对,你得改函数的命名空间:
var func = employeeType.Collection.Function("GetByKey").Returns<Employee>().Parameter<int>("Key");
func.Namespace = "NamespaceX";
然后像 [EnableQuery, HttpGet, ODataRoute("Employees/NamespaceX.GetByKey(Key={Key})")]
这样的 ODataRoute 应该可以工作。
您粘贴的代码有两个问题,
1. 您尝试将函数绑定到 Employees 集合,模型构建不正确。
应该是这样的
var employeeType = builder.EntityType();
员工类型.Collection.Function("GetByKeyFromConfig").Returns().参数("Key");
您可以参考 link https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataFunctionSample 中的示例以了解不同的函数绑定方式。
- 在ODataRoute中,我们要么需要指定带有命名空间的函数,要么通过register方法中的这个配置启用非限定函数调用"config.EnableUnqualifiedNameCall(unqualifiedNameCall: true);"。
参考link http://odata.github.io/WebApi/#03-03-attrribute-routing 搜索不合格
如果这不能解决您的问题,请告诉我。
虽然您可以使用 OData 函数解决您的问题,但更简洁的解决方案是使用 alternate keys. As , Web API OData provides an implementation of alternate keys,它允许您使用更直接的语法按姓名或编号请求员工:
GET /Employees(123)
GET /Employees(Name='Fred')
您需要将以下代码添加到您的 OData 配置中。
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Library;
// config is an instance of HttpConfiguration
config.EnableAlternateKeys(true);
// builder is an instance of ODataConventionModelBuilder
var edmModel = builder.GetEdmModel() as EdmModel;
var employeeType = edmModel.FindDeclaredType(typeof(Employee).FullName) as IEdmEntityType;
var employeeNameProp = employeeType.FindProperty("Name");
edmModel.AddAlternateKeyAnnotation(employeeType, new Dictionary<string, IEdmProperty> { { "Name", employeeNameProp } });
确保在将模型传递给 config.MapODataServiceRoute
之前 添加备用键注释 。
在您的控制器中,添加一个方法来按名称检索员工(与您问题中的 GetByKey
方法非常相似)。
[HttpGet]
[ODataRoute("Employees(Name={name})")]
public IHttpActionResult GetEmployeeByName([FromODataUri] string name)
{
var result = EmployeesHolder.Employees.FirstOrDefault(e => e.Name == name);
if (result == null)
{
return this.NotFound();
}
return this.Ok(result);
}
我是新手,所以我将从代码开始,然后再进行解释。 问题是这个
[HttpGet, ODataRoute("({key})")]
public SingleResult<Employee> GetByKey([FromODataUri] string key)
{
var result = EmployeesHolder.Employees.Where(id => id.Name == key).AsQueryable();
return SingleResult<Employee>.Create<Employee>(result);
}
[HttpGet, ODataRoute("({key})")]
public SingleResult<Employee> Get([FromODataUri] int key)
{
var result = EmployeesHolder.Employees.Where(id => id.Id == key).AsQueryable();
return SingleResult<Employee>.Create<Employee>(result);
}
我有这 2 个操作,但其中一个我想按字符串搜索,另一个我想按数字搜索(尽管这不是问题所在)。如果我这样离开它,它将适用于 (int) 情况,但对于字符串 "....odata/Employees('someName')" 我会得到一个:HTTP 404(这是正常的)但是如果我尝试更具体地使用采用字符串
的方法webApiConfig 中的代码。
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees");
builder.Function("GetByKeyFromConfig").Returns<SingleResult<Employee>>().Parameter<string>("Key");
控制器中的代码
[ODataRoutePrefix("Employees")]
public class FooController : ODataController
{
[HttpGet, ODataRoute("GetByKeyFromConfig(Key={key})")]
public SingleResult<Employee> GetByKey([FromODataUri] string key)
{ ... }
}
我得到了一个期望
{"The complex type 'System.Web.Http.SingleResult`1[[OData_Path.Employee, OData_Path, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' refers to the entity type 'OData_Path.Employee' through the property 'Queryable'."}
如果我在 WebApiConfig
中更改方法的 return 类型builder.Function("GetByKeyFromConfig").Returns<Employee>().Parameter<string>("Key");
我明白了,我不知道为什么。
{"The path template 'Employees/GetByKeyFromConfig(Key={key})' on the action 'GetByKey' in controller 'Foo' is not a valid OData path template. The request URI is not valid. Since the segment 'Employees' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource."}
我已经搜索并试图获得解释,但每次我找到答案都不起作用。我挣扎了好几天。
根据 2 个答案更新后
still have the Invalid OData path template exception
WebApiConfig 代码
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees").EntityType.HasKey(p => p.Name);
var employeeType = builder.EntityType<Employee>();
employeeType.Collection.Function("GetByKey").Returns<Employee>().Parameter<int>("Key");
config.EnableUnqualifiedNameCall(unqualifiedNameCall: true);
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
控制器代码
[EnableQuery, HttpGet, ODataRoute("Employees/GetByKey(Key={Key})")]
public SingleResult<Employee> GetByKey([FromODataUri] int Key)
{
var single = Employees.Where(n => n.Id == Key).AsQueryable();
return SingleResult<Employee>.Create<Employee>(single);
}
我也尝试过使用特定的命名空间
builder.Namespace = "NamespaceX";
[EnableQuery, HttpGet, ODataRoute("Employees/NamespaceX.GetByKey(Key={Key})")]
和
[EnableQuery, HttpGet, ODataRoute("Employees/NamespaceX.GetByKey")]
这篇关于 OData/Webapi 功能支持的文档对您有帮助吗? http://odata.github.io/WebApi/#04-06-function-parameter-support你的第二种方法有问题。
你是用 Employees/GetByKeyFromConfig(Key={key}) 调用的,所以你应该像这样声明函数:
builder.EntityType<Employee>().Collection.Function("GetByKeyFromConfig")
你应该用命名空间调用,比如Employees/yournamespace.GetByKeyFromConfig
第一个场景可以使用这个功能吗? http://odata.github.io/WebApi/#04-17-Alternate-Key
希望对您有所帮助,谢谢。
Update
:
Function declaration is right now, the error message showed because your ODataRoute
is wrong, remove your ODataRoute, 该函数可以调用为 Employees/Default.GetByKey(1)
, WebAPI/OData 可以默认路由到此函数.
或者给ODataRoute添加命名空间,默认是Default
,改成builder.Namespace
不对,你得改函数的命名空间:
var func = employeeType.Collection.Function("GetByKey").Returns<Employee>().Parameter<int>("Key");
func.Namespace = "NamespaceX";
然后像 [EnableQuery, HttpGet, ODataRoute("Employees/NamespaceX.GetByKey(Key={Key})")]
这样的 ODataRoute 应该可以工作。
您粘贴的代码有两个问题, 1. 您尝试将函数绑定到 Employees 集合,模型构建不正确。 应该是这样的 var employeeType = builder.EntityType(); 员工类型.Collection.Function("GetByKeyFromConfig").Returns().参数("Key"); 您可以参考 link https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataFunctionSample 中的示例以了解不同的函数绑定方式。
- 在ODataRoute中,我们要么需要指定带有命名空间的函数,要么通过register方法中的这个配置启用非限定函数调用"config.EnableUnqualifiedNameCall(unqualifiedNameCall: true);"。 参考link http://odata.github.io/WebApi/#03-03-attrribute-routing 搜索不合格
如果这不能解决您的问题,请告诉我。
虽然您可以使用 OData 函数解决您的问题,但更简洁的解决方案是使用 alternate keys. As
GET /Employees(123)
GET /Employees(Name='Fred')
您需要将以下代码添加到您的 OData 配置中。
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Library;
// config is an instance of HttpConfiguration
config.EnableAlternateKeys(true);
// builder is an instance of ODataConventionModelBuilder
var edmModel = builder.GetEdmModel() as EdmModel;
var employeeType = edmModel.FindDeclaredType(typeof(Employee).FullName) as IEdmEntityType;
var employeeNameProp = employeeType.FindProperty("Name");
edmModel.AddAlternateKeyAnnotation(employeeType, new Dictionary<string, IEdmProperty> { { "Name", employeeNameProp } });
确保在将模型传递给 config.MapODataServiceRoute
之前 添加备用键注释 。
在您的控制器中,添加一个方法来按名称检索员工(与您问题中的 GetByKey
方法非常相似)。
[HttpGet]
[ODataRoute("Employees(Name={name})")]
public IHttpActionResult GetEmployeeByName([FromODataUri] string name)
{
var result = EmployeesHolder.Employees.FirstOrDefault(e => e.Name == name);
if (result == null)
{
return this.NotFound();
}
return this.Ok(result);
}