我有这个代码示例,我试图让第三个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)
下面添加第3种方法,我得到"找不到错误404"使用此路线调用/odata/Products('Product 1')
时。如果使用/odata/Products?name='Product 1'
或/odata/Products?name='Product 1'$expand=Vendor
进行调用,则会触发Get()
方法,并且供应商不会再次展开。
感谢您对此的意见。
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()
{
}
}
答案 0 :(得分:2)
因为,#1,#2,#4不起作用,因为操作名称或参数不遵循Web API OData路由约定。约定是一组默认的rules,开发人员应该跟进这些默认值以确保Web API OData可以将请求路由到控制器中的正确方法。
对于#3,因为它使用Web API路由,那是
API / {控制器} / {行动} / {ID}
不使用Web API OData路由。
希望材料here可以帮助您理解Web API OData中的路由。感谢。
答案 1 :(得分:2)
您的代码正在使用OData的ASP.NET实现的built-in routing conventions,而您遇到的问题是这些约定的结果。
在URI路径/odata/Products(1)
中,(1)
部分称为关键细分。按照惯例,key
是用于保存键段值的参数的名称。不幸的是,这与将模型的关键属性命名为Id
的惯例不符。您可以使用attribute routing覆盖此路由约定,但我认为这不值得。
路由惯例是expecting一个名为GetProduct
或仅Get
的方法。同样,您可以使用ODataRouteAttribute
。
检索Products实体集成员的正确URI是/odata/Products(id)
。在我的测试环境中,GET /odata/Products?key=1&$expand=Vendor
未路由到GetByKey
。相反,它被路由到无参数Get
方法,因为它应该根据路由约定(因为请求URI中没有关键段)。
如果Product实体的Name
属性是备用键,则可以利用ASP.NET OData中的alternate key support。您可以按名称检索产品,如下所示:GET /odata/Products(Name='name')
。有关如何在控制器中实现备用密钥的说明,请参阅上一个问题的my answer。