我正在研究如何在ASP.Core中使用OData。
我创建了一个BooksController
的子类,ODataController
的子类,在其中定义了两个动作:Get()
和Get(int id)
。
/odata/books
解析为第一个Action,但是/odata/books(1)
找不到第二个Action。
一旦定义了模型,便可以找到以下控制器:
[ODataRoutePrefix("Books")]
public class BooksController : ODataController
{
private BookStoreContext _db;
public BooksController(BookStoreContext context)
{
_db = context;
}
[ODataRoute]
[EnableQuery]
public IActionResult Get()
{
return Ok(_db.Books);
}
[EnableQuery]
[ODataRoute("({key})")]
public IActionResult Get([FromODataUri] int key)
{
return Ok(_db.Books.FirstOrDefault(c => c.Id == key.ToGuid()));
}
}
该站点具有所有路由的默认“约定”规则(请参见下文)。
但是我认为这没有作用,因为BooksController
用[ODataRoutePrefix("Books")]
装饰,动作用[ODataRoute]
(和[EnableQuery]
)装饰-我认为,这是基于属性的路由,优先(这是正确的假设吗?)。
我的dto模型是使用Reflection ...进行注册的,但是关键部分是Startup调用UseMvc(...)
并定义路由的地方,最终在这里调用:
private void CreateODataRoutes(IRouteBuilder routeBuilder)
{
// register the convention routes for MVC first...
routeBuilder.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
...
// then do the OData stuff...
routeBuilder.Count().Expand().Filter()
.MaxTop(100).OrderBy().Select();
// Use method further down the page
// to create a Build Model by reflection, using
// all OData Model definitions (ie, classes that implement
// IAllModulesOdataModelBuilderConfiguration)
var oDataConventionModelBuilder = BuildODataModelUsingReflectionAcrossAllAssemblies();
// Use the modelBuilder as the basis of defining routes:
RegisterRoutesToODataController(routeBuilder, oDataConventionModelBuilder);
}
BuildODataModelUsingReflectionAcrossAllAssemblies
使用反射来查找各个模型定义,每个模型定义都非常简单,仅定义其ID(其余部分依赖于约定)。
请注意,我并没有按照惯例定义动作(请参阅下文)。
public class BookODataModelBuilderConfigurationBase<T> : IAllModulesOdataModelBuilderConfiguration
where T : class, IHasGuidId, new()
{
public virtual void Apply(ODataModelBuilder builder ...)
{
var _controllerName = this.GetControllerNameByConvention(typeof(Book));
var entity = builder.EntitySet<T>(this._controllerName).EntityType;
entity.HasKey(x => x.Id);
//Note...no Actions defined, as planning to rely on default conventions (routing by Verb to method starting with Get...)
}
}
创建模型后,其注册如下;
private void RegisterRoutesToODataController(IRouteBuilder routeBuilder,
ODataConventionModelBuilder oDataConventionModelBuilder)
{
string routePrefix = $"{App.Modules.Core.Shared.Constants.ModuleSpecific.Module.AssemblyNamePrefix}.";
// Build the Edm model used to parse commands:
var edmModel = oDataConventionModelBuilder.GetEdmModel();
// Register the Odata paths
routeBuilder.MapODataServiceRoute(
routeName: $"{routePrefix}odataDefault",
routePrefix: "odata",
edmModel,
pathHandler:new DefaultODataPathHandler(),
// By convention? So that Get verb goes to Get action, etc.
routingConventions: ODataRoutingConventions.CreateDefault()
);
}
路径为/odata/book(1)
时返回HTTP ERROR 404
,该页面不存在。
谢谢!
我尝试过的其他事情包括:
[FromODataUri]
(有必要吗?)[ODataRoute("({key})")]
BooksController
GetBook
,然后再次更改为Get
ODataRoutePrefix
答案 0 :(得分:0)
OMG。 (嘶哑地)解决了。 它不是Framework,Nuget,Controller基类,routeprefix,route或任何光荣的东西,而是...我。 我唯一看不到的地方是模型本身,该模型将ID定义为Guid。该Action正在使用一个int,将其转换为Guid。 ASP.Core找不到它,因为它是基于模型(而不是控制器)构建路由,因此忽略了Action,因为它对于基于int!= Guid的基于约定的路由构建没有意义。嗯。
如果您想知道为什么我使用int ...那是因为当我为Db播种时,我想要一个Guid Key,但是出于测试目的,我希望某些记录具有特定的ID,我可以参考该ID。 ,而且我很懒惰,不想输入完整的Guid。
回想起来,这是一个愚蠢的主意...:-(
但是感谢您对此进行调查!感激所花费的时间。