【问题标题】:OData get resource by ID and nameOData 通过 ID 和名称获取资源
【发布时间】:2016-03-15 06:20:29
【问题描述】:

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

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

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

  2. 如果我将参数名称放回key,但将方法更改为其他名称,例如GetByKey([FromODataUri] int key),那么上面同样的问题又出现了。

  3. 另外,如果我用/odata/Products?key=1?$expand=Vendor 打电话,电话会转到GetByKey([FromODataUri] int key),但我没有扩展供应商。

  4. 并在GetByName([FromODataUri] string name) 下方添加第三种方法,当使用此路由/odata/Products('Product 1') 调用时,我得到“找不到错误404”。如果使用/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()
    {

    }
}

【问题讨论】:

    标签: asp.net-web-api odata


    【解决方案1】:

    您的代码正在使用 OData 的 ASP.NET 实现的 built-in routing conventions,而您遇到的问题是这些约定的结果。

    1. 在 URI 路径 /odata/Products(1) 中,(1) 部分称为键段。按照约定,key 是用于保存键段值的参数名称。不幸的是,这不符合将模型的关键属性命名为Id 的约定。您可以使用attribute routing 覆盖此路由约定,但在我看来这不值得。

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

    3. 用于检索 Products 实体集成员的正确 URI 是 /odata/Products(<i>id</i>)。在我的测试环境中,GET /odata/Products?key=1&amp;$expand=Vendor 没有路由到GetByKey。相反,它被路由到无参数的Get 方法,因为它应该根据路由约定(因为请求 URI 中没有关键段)。

    4. 如果 Product 实体的 Name 属性是备用键,则可以利用 ASP.NET OData 中的 alternate key support。您可以按以下名称检索产品:GET /odata/Products(Name='<i>name</i>')。有关如何在控制器中实现备用键的说明,请参阅上一个问题的 my answer

    【讨论】:

    • 感谢您的意见,非常棒!我查看了备用键并且不喜欢必须编写代码来定义每个模型及其键/属性等的事实......所以,我最终做的只是将 [Key] 属性添加到 Name 属性在我的视图模型中。
    • 如果我的帖子有帮助,请考虑投票或接受它作为答案。
    • 一旦它让我(获得我的 15 个声望),我会很高兴。
    【解决方案2】:

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

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

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

    不使用 Web API OData 路由。

    希望here的资料可以帮助你理解Web API OData中的路由。谢谢。

    【讨论】:

    • 问题 #3 与 Web API 路由无关。这些路由以/api 为前缀,而OData 路由以/odata 为前缀。
    • 好的。有没有漏掉$expand前面的“&”:/odata/Products?key=1&$expand=Vendor 但是正确的请求Uri应该是:~/odata/Products(1)?$expand=Vendor
    • 谢谢大家,是的,山姆,我确实忘记了“&”,谢谢你赶上了。您对 /odata/Products(1)?$expand=Vendor. 的正确 URI 是正确的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 2011-03-29
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    相关资源
    最近更新 更多