OData,Net5:当控制器return多种类型的实体时如何实现$count

OData, Net5: How to implement $count when controllers return entities of multiple types

我正在将 OData 添加到 .Net5 中现有的大型 API,其中每个控制器中的操作方法 return 不同类型(例如 OrganizationFull、OrganizationList 等)

这是有效的,除了响应不包含 OData 元数据,例如 $count。因此,当消费者调用 /api/OrganizationList?$count=true 时,它​​不会得到计数。

我了解要获取此元数据,我必须添加一个 EDM 模型,如下所示:

// Startup.cs

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers()
                .AddOData(opt => opt.Select().Filter().Count().SetMaxTop(10).AddRouteComponents("odata", GetEdmModel()))


        IEdmModel GetEdmModel()
        {
            var odataBuilder = new ODataConventionModelBuilder();

            odataBuilder.EntitySet<OrganizationFull>(nameof(Organization));
            odataBuilder.EntitySet<OrganizationList>(nameof(Organization)); // throws
            return odataBuilder.GetEdmModel();
        }


这里我指定了 2 个 EntitySet,每个实体类型一个 return来自 OrganizationController。

但是,这会引发异常“实体集 'Organization' 已经配置了不同的 EntityType ('OrganizationFull')。”。如果我删除 OrganizationList 的 EntitySet,当我到达列表端点时,我会收到 404。

如何让我的终点指向 return $count 元数据,同时保持我的 API(来自一个控制器的 return 多个实体类型)?

或者,有没有办法从 OData 基础结构中获取操作方法中的计数?在那种情况下,我可以 return 它在响应中 header.

尝试将 .Count() 添加到 AddOData 方法调用:

           .AddOData(opt => opt.Select().Filter().Count().SetMaxTop(10).AddRouteComponents("odata", GetEdmModel()))

经过一些挖掘,我找到了一种方法来从 OData 库中获取计数,而无需为其提供 EDM 模型,也无需更改 API 的 JSON 响应(即,不添加 OData 元数据)。

这适用于 Microsoft.AspNetCore.OData 版本 8.0.1。

事实证明,此库公开的 EnableQueryAttribute 过滤器的 OnActionExecuted 方法将计数与 http 上下文相关联。你可以覆盖这个方法,检索计数,然后用它做你想做的事(比如创建一个响应头):

public partial class EnableQueryWithCountAttribute: EnableQueryAttribute
{
    public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);

        HttpContext context = actionExecutedContext.HttpContext;

        // TotalCount will be null if 1) Count is not enabled during startup; and 2) if
        // $count=true is not used in the url.

        long? count = context.Request.ODataFeature().TotalCount;
        if (count.HasValue)
        {
            // Here you could do something with count, 
            // such as adding it to the response using a response header.
        }
    }
}

然后您将使用新属性而不是 EnableQuery 来装饰您的端点。例如:

[EnableQueryWithCount]
public virtual ActionResult<IQueryable<T>> Get()
{
    ...
}