Asp.net web api OData按ID和名称获取资源

Asp.net web api OData按ID和名称获取资源,asp.net-web-api,odata,Asp.net Web Api,Odata,我有一个代码示例,我正在尝试使第三个Get方法工作,还有$expand工作,如下所述 如果我只有方法Get()和Get([FromODataUri]int key),我可以使用这些各自的路由/odata/Products和/odata/Products(1)?$expand=Vendor调用它们。 但是,当我进行以下更改时,我会遇到以下问题 如果我只将参数名key更改为id或方法Get([FromODataUri]int key)中的任何其他内容,则不再调用该方法。/odata/Products

我有一个代码示例,我正在尝试使第三个Get方法工作,还有
$expand
工作,如下所述

如果我只有方法
Get()
Get([FromODataUri]int key)
,我可以使用这些各自的路由
/odata/Products
/odata/Products(1)?$expand=Vendor
调用它们。 但是,当我进行以下更改时,我会遇到以下问题

  • 如果我只将参数名
    key
    更改为
    id
    或方法
    Get([FromODataUri]int key)
    中的任何其他内容,则不再调用该方法。
    /odata/Products(1)
    的路由调用转到总是返回所有集合的
    Get()
    方法

  • 如果我将参数名称放回
    key
    ,但将方法更改为其他方法,例如
    GetByKey([FromODataUri]int key)
    ,则上述相同问题再次发生

  • 另外,如果我使用
    /odata/Products?key=1?$expand=Vendor
    进行调用,则调用将转到
    GetByKey([FromODataUri]int key)
    ,但我不会扩展供应商

  • 在下面添加第三个方法
    GetByName([FromODataUri]string name)
    ,使用此路由调用时,我会得到“error 404 not found”,即
    /odata/Products('Product 1')
    。如果使用
    /odata/Products?name='Product 1'
    /odata/Products?name='Product 1'$expand=Vendor
    调用,则会触发
    Get()
    方法,并且Vendor不会再次展开

  • 我将非常感谢你在这方面的意见

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
    
            // Web API routes
            config.MapHttpAttributeRoutes();
    
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            ODataModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Product    ("Products");
            config.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());
    
        }
    }
    
    public class ProductsController : ODataController
    {
        #region 
    
        ProductsContext db = new ProductsContext();
        private bool ProductExists(int key)
        {
            return db.Products.Any(p =     p.Id == key);
        }
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    
        #endregion
    
        [HttpGet]
        [EnableQuery]
        public IQueryable<Product     Get()
        {
            return db.Products.AsQueryable();
        }
    
        [HttpGet]
        [EnableQuery]
        public SingleResult<Product     Get([FromODataUri] int key)
        {
            IQueryable<Product     result = db.Products.Where(p =     p.Id == key).AsQueryable();
            return SingleResult.Create(result);
        }
    
        [HttpGet]
        [EnableQuery]
        public SingleResult<Product     GetByName([FromODataUri] string name)
        {
            IQueryable<Product     result = db.Products.Where(p =     p.Name == name).AsQueryable();
            return SingleResult.Create(result);
        }
    }
    
    public class Product
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
    
        public decimal Price { get; set; }
    
        public string Category { get; set; }
    
        public Vendor Vendor { get; set; }
    
    }
    
    public class Vendor
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
    
    }
    
    public class ProductsContext : IDisposable
    {
        public ICollection<Product     Products = new List<Product    ()
        {
            new Product()
            {
                Category = "A",
                Id = 1,
                Name = "Product 1",
                Price = 10,
                Vendor = new Vendor()
                {
                    Id = 1,
                    Name = "Vendor 1"
                }
            },
    
            new Product()
            {
                Category = "A",
                Id = 2,
                Name = "Product 2",
                Price = 15,
                Vendor = new Vendor()
                {
                    Id = 1,
                    Name = "Vendor 1"
                }
            },
    
            new Product()
            {
                Category = "B",
                Id = 3,
                Name = "Product 3",
                Price = 10,
                Vendor = new Vendor()
                {
                    Id = 2,
                    Name = "Vendor 2"
                }
            },
        };
    
        public void Dispose()
        {
    
        }
    }
    
    公共静态类WebApiConfig
    {
    公共静态无效寄存器(HttpConfiguration配置)
    {
    //Web API配置和服务
    //Web API路由
    config.maphttpAttribute路由();
    config.Routes.MapHttpRoute(
    名称:“DefaultApi”,
    routeTemplate:“api/{controller}/{action}/{id}”,
    默认值:新建{id=RouteParameter.Optional}
    );
    ODataModelBuilder=新ODataConventionModelBuilder();
    #1、#2、#4的builder.EntitySet不起作用,因为操作名称或参数不遵循Web API OData路由约定。约定是开发人员应遵循的一组默认设置,以确保Web API OData可以将请求路由到控制器中的正确方法

    对于#3,因为它使用Web API路由,所以

    api/{controller}/{action}/{id}

    不要使用Web API OData路由

    希望这些资料能帮助您理解Web API OData中的路由。谢谢。

    对于、#1、#2、#4,它们不起作用,因为操作名称或参数不遵循Web API OData路由约定。约定是开发人员应该遵循的一组默认设置,以确保Web API OData可以将请求路由到中的正确方法控制器

    对于#3,因为它使用Web API路由,所以

    api/{controller}/{action}/{id}

    不要使用Web API OData路由

    希望本资料能帮助您理解Web API OData中的路由。谢谢。

    您的代码使用的是OData的ASP.NET实现,您遇到的问题是这些约定的结果

  • 在URI路径
    /odata/Products(1)
  • 部分称为键段。按照惯例,
    key
    是用于保存键段值的参数的名称。不幸的是,这与将模型的键属性命名为
    Id
    的惯例不匹配。您可以使用来覆盖此路由约定,但这不值得在我的opin中付出努力离子

  • 路由约定是名为
    GetProduct
    或只是
    Get
    的方法。同样,您可以使用
    ODataRouteAttribute
    覆盖常规行为

  • 用于检索产品实体集成员的适当URI是
    /odata/Products(id)
    。在我的测试环境中,
    GET/odata/Products?key=1&$expand=Vendor
    没有路由到
    GetByKey
    。相反,它被路由到无参数的
    GET
    方法,因为它应该符合路由约定(因为请求URI中没有键段)

  • 如果产品实体的
    Name
    属性是备用密钥,则您可以利用ASP.NET OData中的。您可以按名称检索产品,如下所示:
    GET/OData/Products(Name='Name')
    。有关如何在控制器中实现备用密钥的说明,请参阅前面的问题

  • 您的代码使用的是OData的ASP.NET实现,您遇到的问题是这些约定的结果

  • 在URI路径
    /odata/Products(1)
    中部分称为键段。按照惯例,
    key
    是用于保存键段值的参数的名称。不幸的是,这与将模型的键属性命名为
    Id
    的惯例不匹配。您可以使用来覆盖此路由约定,但这不值得在我的opin中付出努力离子

  • 路由约定是名为
    GetProduct
    或只是
    Get
    的方法。同样,您可以使用
    ODataRouteAttribute
    覆盖常规行为

  • 用于检索产品实体集成员的适当URI是
    /odata/Products(id)
    。在我的测试环境中,
    GET/odata/Products?key=1&$expand=Vendor
    没有路由到
    GetByKey
    。相反,它被路由到无参数的
    GET
    方法,因为它应该符合路由约定(因为请求URI中没有键段)

  • 如果产品实体的
    Name
    属性是备用键,则可以使用advantag