我对此并不陌生,因此我将从代码开始,然后我将进行解释。
问题是

[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);
}

10-08 14:50