OData 路由异常

本文关键字:异常 路由 OData | 更新日期: 2023-09-27 18:37:12

我是新手,所以我将从代码开始,然后我将解释。问题是这个

[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, 版本=1.0.0.0,区域性=中性,公钥令牌=空]]' 指 实体类型"OData_Path.Employee"通过属性"可查询"。

如果我在 WebApiConfig 中更改该方法的返回类型

builder.Function("GetByKeyFromConfig").Returns<Employee>().Parameter<string>("Key");

我明白这个我不知道为什么。

{"路径模板'Employees/GetByKeyFromConfig(Key={key})' 控制器"Foo"中的操作"GetByKey"不是有效的 OData 路径 模板。请求 URI 无效。由于"员工"细分市场 引用集合,这必须是请求中的最后一个段 URI 或它后面必须跟有可以绑定的函数或操作 否则所有中间段都必须引用单个 资源。

我已经搜索并试图得到解释,但每次我找到答案都不起作用。 我挣扎了好几天。


从 2 个答案中获取更新后

仍有无效的 OData 路径模板例外

WebApiConfig Code

 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 路由异常

虽然您可以使用 OData 函数解决问题,但更干净的解决方案是使用备用键。正如 Fan 所指出的,Web API OData 提供了备用键的实现,允许您使用更直接的语法按姓名或编号请求员工:

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

这个关于 OData/Webapi 的函数支持的文档能帮助你吗? http://odata.github.io/WebApi/#04-06-function-parameter-support 您的第二种方法存在一些问题。

  1. 你被调用 Employees/GetByKeyFromConfig(Key={key}),所以你应该声明这样的函数:

    builder.EntityType<Employee>().Collection.Function("GetByKeyFromConfig") 
    
  2. 你应该使用命名空间调用,比如 Employees/yournamespace。GetByKeyFromConfig

第一种情况可以使用此功能吗?http://odata.github.io/WebApi/#04-17-Alternate-Key

希望这能有所帮助,谢谢。

Update :函数声明是现在,显示的错误消息是因为你的ODataRoute错误,删除你的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.您尝试将函数绑定到员工集合,模型构建不正确。它应该是这样的 var employeeType = builder。实体类型();员工类型 .Collection.Function("GetByKeyFromConfig").返回()。参数("键");您可以参考链接 https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataFunctionSample 中的示例,了解绑定函数的不同方法。

  1. 在 ODataRoute 中,我们要么需要使用命名空间指定函数,要么在注册方法"config.EnableUnqualifiedNameCall(unqualifiedNameCall: true);".请参阅链接 http://odata.github.io/WebApi/#03-03-attrribute-routing 并搜索不合格。

如果这不能解决您的问题,请告诉我。