两个操作的属性路由导致“无效的OData路径模板”

时间:2018-05-15 12:47:00

标签: asp.net-mvc odata attributerouting

所以我有两个函数返回一个客户,它由两个不同的参数提供。一个是客户的ID,另一个是他的客户编号。

我的控制器:

using System.Linq;
using System.Net;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Routing;
using Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using System.Web.OData.Extensions;
using Importing;
using Objects;
using Microsoft.OData;

namespace Controllers
{
    public class CustomersController : ODataController
    {
        // GET: CustomerByCNO(5)
        [HttpGet]
        [ODataRoute("CustomerByCNO({key})")]
        [EnableQuery]
        public SingleResult<CustomerDTO> GetCustomerByCNO([FromODataUri]string key)
        {
            Import i = new Import();

            var customer = i.GetCustomer(key).ProjectTo<CustomerDTO>().AsQueryable();

            return SingleResult.Create(customer);
        }

        // GET: Customer(5)
        [HttpGet]
        [ODataRoute("Customer({id})")]
        [EnableQuery]
        public SingleResult<CustomerDTO> Get([FromODataUri]int id)
        {
            Import i = new Import();

            var customer = i.GetCustomer(id).ProjectTo<CustomerDTO>().AsQueryable();

            return SingleResult.Create(customer);
        }
    }
}

初​​始化:

using AutoMapper;
using Models;
using Objects;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using Microsoft.OData.Edm;

namespace API
{
    public static class WebApiConfig
    {
        public static void ConfigureAPI(HttpConfiguration config)
        {
            config.MapODataServiceRoute(
                routeName: "odata",
                routePrefix: "",
                model: GetEdmModel()
            );

            config.EnsureInitialized();
        }

        private static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder
            {
                Namespace = "Controllers",
                ContainerName = "DefaultContainer"
            };
            builder.EntitySet<CustomerDTO>("Customer")
                .EntityType.HasKey(c => c.Id)
                .CollectionProperty(c => c.CustomFields);

            var edmModel = builder.GetEdmModel();
            return edmModel;
        }
    }
}

虽然第二个函数按预期工作,但第一个函数没有,而EnsureInitialized()函数抛出一个InvalidOperationException,说它没有有效的OData路径模板,也没有找到资源。我怎样才能使这个工作?不太清楚我在这里缺少什么。

更新1:

将Controller方法更改为:

        [HttpGet]
        [ODataRoute("CustomerByNo(No={no})")]
        public SingleResult<CustomerDTO> CustomerByNo([FromODataUri] int no)
        {
            Import i = new Import();

            var customer = i.GetCustomer(no.ToString()).ProjectTo<CustomerDTO>().AsQueryable();

            return SingleResult.Create(customer);
        }

使用配置中的这一附加行:

        builder.Function("CustomerByNo").Returns<SingleResult<CustomerDTO>>().Parameter<int>("No");

这样做我至少可以访问这些功能。我不得不将参数更改为int,似乎它不喜欢字符串?但是,返回值不会反序列化并像往常一样显示。此外,如果我在方法声明中保留[EnableQuery]行,则调用将崩溃,说它不知道如何反序列化,因为它不绑定到Customer的实体集我猜。

然而,尝试这种方式会导致原始错误消息,即无法找到资源:

        builder.EntityType<CustomerDTO>().Collection.Function("CustomerByNo").Returns<SingleResult<CustomerDTO>>().Parameter<int>("No");

1 个答案:

答案 0 :(得分:1)

您必须在约定模型中声明自定义odata函数:

FunctionConfiguration customerByCNOFunction = builder.Function("CustomerByCNO");
customerByCNOFunction.Returns<CustomerDTO>();
customerByCNOFunction.Parameter<string>("key");

更新:

我的第一个答案是声明一个返回odata中不可查询的类型的函数。 要启用查询,该函数需要从实体集返回odata实体:

builder.Function("CustomerByNo").ReturnsFromEntitySet<CustomerDTO>("Customer").Parameter<int>("No")