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

如何编写在UseFiltering之后执行的HotChocolate中间件?

问题:在HotChocolate v13中编写获取过滤后IQueryable的字段中间件

基于现有.NET WebAPI使用HotChocolate v13构建GraphQL接口时,为带有UseFiltering()的字段编写自定义中间件,在调用await next(context)前后断点查看context.Result,发现始终是未应用过滤的原始IQueryable<Product>,无法获取客户端过滤后的结果。

代码示例:

public class QueryType : ObjectType<Query>
{
    protected override void Configure(IObjectTypeDescriptor<GraphQuery> descriptor)
    {
        descriptor.Authorize();

        descriptor
            .Field(x => x.GetProducts(default!, default!))
            .UseFiltering()
            .Use(next => async context =>
            {
                // 断点:context.Result 为 null
                await next(context);
                // 断点:context.Result 是未过滤的 AppDbContext.Products
            })
            .Type<ListType<ProductType>>();

        base.Configure(descriptor);
    }
}

public class Query
{
    public IQueryable<Product> GetProducts([Service] AppDbContext dbContext, [ScopedService] ICurrentUser currentUser)
    {
        return dbContext.Products;
    }
}

解决方案

核心问题是中间件的注册顺序:HotChocolate的中间件按注册顺序链式执行,你当前把自定义中间件放在UseFiltering()之后,导致过滤逻辑还未执行就进入了自定义中间件,调用next(context)才会触发过滤,但此时拿到的仍是原始IQueryable(过滤逻辑是对IQueryable做表达式包装,而非立即执行查询)。

要获取过滤后的IQueryable,需将自定义中间件注册在UseFiltering()之前:

public class QueryType : ObjectType<Query>
{
    protected override void Configure(IObjectTypeDescriptor<GraphQuery> descriptor)
    {
        descriptor.Authorize();

        descriptor
            .Field(x => x.GetProducts(default!, default!))
            // 先注册自定义中间件
            .Use(next => async context =>
            {
                await next(context);
                // 此时 context.Result 就是应用了客户端过滤条件的 IQueryable<Product>
                var filteredProducts = context.Result as IQueryable<Product>;
                // 可在此对过滤后的IQueryable做额外处理,比如追加自定义过滤
                // context.Result = filteredProducts.Where(p => p.IsActive);
            })
            .UseFiltering()
            .Type<ListType<ProductType>>();

        base.Configure(descriptor);
    }
}

原理说明

  1. 自定义中间件先注册,执行时先进入其逻辑,调用await next(context)会将执行权传递给后续的UseFiltering()中间件。
  2. UseFiltering()中间件解析客户端过滤参数,将过滤表达式应用到原始IQueryable<Product>上,生成带过滤条件的新IQueryable并赋值给context.Result。
  3. 执行权回到自定义中间件,此时context.Result就是已应用过滤的IQueryable,可在此进行后续操作。

注意:IQueryable是延迟执行的,此时看到的context.Result是带有过滤表达式的查询对象,数据库查询会在后续执行环节才真正触发。


内容的提问来源于stack exchange,提问作者Alberto Cruz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:32:11