我对此并不陌生,因此我将从代码开始,然后我将进行解释。
问题是
[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);
}
我有这两个动作,但是对于一个我想按字符串搜索,而对于另一个按数字搜索(尽管这不是问题)。如果我以这种方式离开它,它将适用于(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)
{ ... }
}
我得到了期望
{“复杂类型
'System.Web.Http.SingleResult`1 [[OData_Path.Employee,OData_Path,
Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]'是指
实体类型“ OData_Path.Employee”通过属性“ Queryable”。“}
如果我更改WebApiConfig中方法的返回类型
builder.Function("GetByKeyFromConfig").Returns<Employee>().Parameter<string>("Key");
我明白了,我不知道为什么。
{“路径模板'Employees / GetByKeyFromConfig(Key = {key})
控制器“ Foo”中的操作“ GetByKey”不是有效的OData路径
模板。请求URI无效。由于“员工”细分
引用一个集合,它必须是请求中的最后一个段
URI或它后面必须是可以绑定的函数或动作
否则,所有中间段都必须引用一个
资源。”}
我已经搜索并尝试获取解释,但是每次我找到答案都行不通。我挣扎了好几天。
从2个答案中获取更新后
仍然具有无效的OData路径模板异常
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函数解决问题,但更干净的解决方案是使用alternate keys。作为Fan indicated,Web API OData提供了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);
}