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()
{
...
}
我正在将 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()
{
...
}