.Net WebApi OData控制器中的多个get方法
我想知道是否有可能在同一个ODataController中使用参数实现两种不同的get方法。这就是我试图做的,但它不起作用。我能做什么 在ODataController中:.Net WebApi OData控制器中的多个get方法,.net,asp.net-web-api,odata,.net,Asp.net Web Api,Odata,我想知道是否有可能在同一个ODataController中使用参数实现两种不同的get方法。这就是我试图做的,但它不起作用。我能做什么 在ODataController中: public class ProductsController : ODataController { private readonly ProductsService _service; public ProductsController() { _service = ne
public class ProductsController : ODataController
{
private readonly ProductsService _service;
public ProductsController()
{
_service = new ProductsService();
}
[EnableQuery]
public IQueryable<Product> Get()
{
return _service.GetAll();
}
[EnableQuery]
public Product Get(int key)
{
return _service.GetById(key);
}
[EnableQuery]
public IQueryable<Product> Get(string key)
{
return _service.GetByFilter(key);
}
公共类产品控制器:ODataController
{
私有只读产品服务;
公共产品控制器()
{
_服务=新产品服务();
}
[启用查询]
公共IQueryable Get()
{
return_service.GetAll();
}
[启用查询]
公共产品获取(int键)
{
return _service.GetById(key);
}
[启用查询]
公共IQueryable获取(字符串键)
{
return\u service.GetByFilter(键);
}
在WebApiConfig.cs文件中,我有下一个配置:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
config.Routes.MapODataServiceRoute("odata", "api/odata", builder.GetEdmModel());
ODataModelBuilder=new ODataConventionModelBuilder();
建筑商实体集(“产品”);
config.Routes.MapODataServiceRoute(“odata”,“api/odata”,builder.getedModel());
我可以将不带参数的“get”方法与带参数的“get”方法一起使用,但我不能将这两种方法与带参数的“get”方法一起使用。我看过OdataRoute,但没有找到函数。我知道我可以将OData筛选器功能与泛型方法一起使用,但我想尝试不使用它。是否有其他解决方案
谢谢!OData路由不支持重载OOTB这正是您在这里描述的两个
GET Collection
方法,但您希望其中一个与GET Resource
方法具有相同的路由
第一个问题是,为什么希望相同的路由指向两个不同的方法,特别是当其中一个路由返回单个资源,而另一个路由将返回集合时
内置约定将已知URL路由到与预期签名匹配的方法。所有其他路由都需要作为离散函数或操作在Edm模型中注册。您也可以实现自己的路由 如果您打算让
Get(字符串键)
返回单个项目或集合,则参数大致相同。默认路由与处理该路由请求的两种不同方法之间仍然存在冲突。对于此类问题,存在直接重复issue on:
在OData中,我们将符合默认~/Controller(key)
路由的资源的键与有效的所有其他路由进行区分。对于所有其他非默认路由,我们只需在OData EDM模型中声明它们即可使其有效
还有其他可能的解决方案,如或。
然而,我发现最好尽量坚持OData标准约定,因此当遇到路由问题时,可以在OData传统方式和我们的业务需求之间定义一个简单的映射,并且您希望在全球范围内支持此语法,那么您可以使用一个简单的url重写模块
在Edm模型中将自定义方法端点声明为单独的函数
创建Url重写以在旧路由和OData路由之间映射
在Edm模型中声明自定义函数:
要通过Edm模型访问自定义功能,我们需要进行两项更改:
将方法名称更改为非Get
。在本例中,我们将使用术语Search
[HttpGet]
[EnableQuery]
public IQueryable<Product> Search(string key)
{
return _service.GetByFilter(key);
}
Url重写模块
如果可以,请尝试使用约定。选择OData是有原因的。如果确实使用重写模块,请在条件逻辑中尽量具体,以避免破坏可能正在使用的其他标准路由
我尝试为常见的遗留查询路由保留重写解决方案
我们是否可以假设您的模型有一个整数主键
字段?是否有一些背景资料说明您为什么要这样做?因为它与OData标准路由约定直接冲突,很难确定您的请求是由于对约定的无知,还是您有合理的业务需求。请同时提供示例URL和关于如何区分整数键和字符串键的推理。更糟糕的是,您在字符串版本中甚至没有使用key
参数,因此不清楚您的实际意图。嗨,克里斯!非常感谢您的回答。答案太完整了。是的,我被要求尝试这样做,为了避免通过url传递一些api信息。您是对的,示例中有一个错误,它在函数“GetByFilter”中使用了一个关键参数。我将立即进行编辑。我要求的原因是REST api为同一路由赋予多个含义是违反直觉的。这会造成文档混乱,但会导致错误lso OData客户端将无法理解非常规端点。我试图确定您是否愿意为该功能使用不同的路径,因为这是我们在OData中的操作方式,我们向控制器添加操作和功能,以构建一组丰富的行为和对象图Hi Chris!再次感谢您的nswer。它太完整了。我已尝试实现您的示例,但在“products.EntityType.Collection.Function…”中配置ODataModel.In时遇到问题。我遇到以下错误:“EntityCollectionConfiguration”不包含“Function”的定义,并且没有可访问的扩展方法“Function”接受第一个参数找不到类型为“EntityCollectionConfiguration”的ent。您知道为什么会发生这种情况吗?再次感谢!!请尝试使用Microsoft.AspNet.OData.Builder添加,这是Microsoft.AspNet.OData.7.5.2包中的
ODataModelBuilder builder = new ODataConventionModelBuilder();
var products = builder.EntitySet<Product>("Products");
products.EntityType.Collection.Function(nameof(ProductsController.Search))
.ReturnsCollectionFromEntitySet<Facility>("Products")
.Parameter<string>("key");
config.Routes.MapODataServiceRoute("odata", "api/odata", builder.GetEdmModel());
public class ODataConventionUrlRewriter : OwinMiddleware
{
/// <summary>
/// Create a Url Rewriter to manipulate incoming OData requests and rewrite or redirect to the correct request syntax
/// </summary>
/// <param name="next"></param>
public ODataConventionUrlRewriter(OwinMiddleware next)
: base(next)
{
}
/// <summary>
/// Process the incoming request, if it matches a known path, rewrite accordingly or redirect.
/// </summary>
/// <param name="context">OWin Request context to process</param>
/// <returns>Chains the next processor if the url is OK or rewritten, otherwise the response is to redirect</returns>
public override async Task Invoke(IOwinContext context)
{
// Match ANY /Controller(NonNumeric)
// Rewrite to /Controller/Search(key='NonNumeric')
var regex = new System.Text.RegularExpressions.Regex(@"\(([^\d=\'\(]+)\)$");
match = regex.Match(context.Request.Path.Value);
if (match != null && match.Success)
{
// We have to use redirect here, we can't affect the query inflight
context.Response.Redirect($"{context.Request.Uri.GetLeftPart(UriPartial.Authority)}{regex.Replace(context.Request.Path.Value, $"/Search(key='{match.Groups[1].Value}')")}");
}
else
await Next.Invoke(context);
}
}
public void Configuration(IAppBuilder app)
{
...
// Rewrite URLs
app.Use(typeof(ODataConventionUrlRewriter));
...
// Register routes
config.MapHttpAttributeRoutes();
ODataModelBuilder builder = new ODataConventionModelBuilder();
var products = builder.EntitySet<Product>("Products");
products.EntityType.Collection.Function(nameof(ProductsController.Search))
.ReturnsCollectionFromEntitySet<Facility>("Products")
.Parameter<string>("key");
config.Routes.MapODataServiceRoute("odata", "api/odata", builder.GetEdmModel());
...
// Start Web API
app.UseWebApi(config);
}