You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 02:47:38