.NET 6中如何为自定义OData API动态分配泛型控制器
在.NET Core OData中实现泛型控制器路由方案
步骤1:创建泛型控制器
定义继承ODataController的泛型控制器,实现OData标准动作:
public class GenericController<T> : ODataController where T : class { [EnableQuery] public IActionResult Get() { // 替换为实际数据获取逻辑 return Ok(Enumerable.Empty<T>()); } public IActionResult Post([FromBody] T entity) { if (!ModelState.IsValid) { return BadRequest(ModelState); } // 替换为实际数据创建逻辑 return Created(entity); } // 可按需添加Put、Delete等OData动作 }
步骤2:实现自定义控制器选择器
.NET Core中通过IControllerSelector替代ASP.NET 4.8的IHttpControllerSelector,完成路由到泛型控制器的匹配:
public class GenericControllerSelector : IControllerSelector { private readonly IControllerTypeCache _controllerTypeCache; private readonly IEnumerable<EntitySetConfiguration> _entitySets; private readonly Dictionary<string, Type> _controllerMappings = new(); public GenericControllerSelector(IControllerTypeCache controllerTypeCache, IEnumerable<EntitySetConfiguration> entitySets) { _controllerTypeCache = controllerTypeCache; _entitySets = entitySets; // 预构建实体名称与泛型控制器的映射 foreach (var set in _entitySets) { var entityType = set.ClrType; var controllerType = typeof(GenericController<>).MakeGenericType(entityType); _controllerMappings.Add(entityType.Name.ToLowerInvariant(), controllerType); } } public ControllerModel? SelectController(ActionContext context) { // 从路由中提取控制器名称(如/MyCustomType中的MyCustomType) if (!context.RouteData.Values.TryGetValue("controller", out var controllerValue) || controllerValue is not string controllerName) { return null; } var lowerControllerName = controllerName.ToLowerInvariant(); if (_controllerMappings.TryGetValue(lowerControllerName, out var controllerType)) { var controllerModels = _controllerTypeCache.GetControllerTypes(); return controllerModels.FirstOrDefault(m => m.ControllerType == controllerType); } return null; } public IEnumerable<ControllerModel> GetControllerTypes() { var controllerModels = _controllerTypeCache.GetControllerTypes(); return controllerModels.Concat(_controllerMappings.Values.Select(type => new ControllerModel(type, Array.Empty<object>()))); } }
步骤3:注册服务与配置OData
在Program.cs中完成服务注册和路由配置:
var builder = WebApplication.CreateBuilder(args); // 添加OData服务并配置查询支持 builder.Services.AddControllers().AddOData(options => { options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(100); var edmModel = BuildEdmModel(); options.AddRouteComponents("odata", edmModel); }); // 注册自定义控制器选择器 builder.Services.AddSingleton<IControllerSelector, GenericControllerSelector>(); // 注册泛型控制器到依赖注入容器 builder.Services.AddTransient(typeof(GenericController<>)); // 构建EDM模型(替换为你的实体集配置逻辑) static IEdmModel BuildEdmModel() { var modelBuilder = new ODataConventionModelBuilder(); // 示例:遍历EntitySetConfiguration添加实体集 // foreach(var set in entitySets) modelBuilder.EntitySet(set.ClrType, set.Name); return modelBuilder.GetEdmModel(); } var app = builder.Build(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapODataRoute("odata", "odata", options => { options.EnableDependencyInjection(); options.RouteOptions.EnableUnqualifiedNameCall = true; }); // 配置匹配实体名称的路由规则 endpoints.MapControllerRoute( name: "generic_entity", pattern: "{controller}", defaults: new { action = "Get" } ); }); app.Run();
关键说明
- 确保EDM模型中已注册所有需要路由的实体集,OData才能正确处理元数据和查询请求
- 自定义控制器选择器会自动将
/MyCustomType这类路由匹配到GenericController<MyCustomType>
内容的提问来源于stack exchange,提问作者avenmia
相关产品推荐
相关产品推荐

