如何通过IoC访问HotChocolate的QueryRequest以优化SQL查询性能
IReadOnlyQueryRequest Without IHttpContextAccessor Great question! Your current approach using HttpContext.Items works, but it ties your code tightly to ASP.NET Core's IHttpContextAccessor—which can make testing more cumbersome and couples your business/data logic to the web layer. HotChocolate provides native, cleaner alternatives to access the IReadOnlyQueryRequest across your application layers.
Option 1: Use HotChocolate's IScopedContextProvider (Recommended)
HotChocolate includes a built-in scoped context system designed to share data across the request execution pipeline without relying on HttpContext. Here's how to implement it:
Step 1: Store the Request in Scoped Context
Update your query request interceptor to use IScopedContextProvider instead of HttpContext.Items:
services.AddQueryRequestInterceptor(GraphQLRequestInterceptor); // ... private Task GraphQLRequestInterceptor(HttpContext context, IQueryRequestBuilder requestBuilder, CancellationToken cancellationToken) { IReadOnlyQueryRequest request = requestBuilder.Create(); // Get the scoped context provider from the request's service scope var scopedContext = context.RequestServices.GetRequiredService<IScopedContextProvider>(); // Store the request in the scoped context with a unique key scopedContext.Set("GraphQL_QueryRequest", request); return Task.CompletedTask; }
Step 2: Retrieve the Request in Your Service
Inject IScopedContextProvider directly into your ClientesQueries class to access the request:
public class ClientesQueries { private readonly IReadOnlyQueryRequest? _queryRequest; public ClientesQueries(IScopedContextProvider scopedContextProvider) { // Safely retrieve the request from the scoped context if (scopedContextProvider.TryGet("GraphQL_QueryRequest", out IReadOnlyQueryRequest? request)) { _queryRequest = request; } } // Use _queryRequest to build your optimized database queries... }
Why This Is Better:
- Decoupled from ASP.NET Core: No dependency on
IHttpContextAccessor, so your logic isn't tied to web-specific infrastructure. - Easier Testing: You can mock
IScopedContextProviderin unit tests without needing to spin up a fullHttpContext. - HotChocolate-Native: Aligns with the framework's built-in patterns for request-scoped data sharing.
Option 2: Access the Request Directly in Resolvers (If Applicable)
If your ClientesQueries is directly used by GraphQL resolvers, you can skip the interceptor entirely and fetch the request from the resolver context:
public async Task<Cliente> GetCliente(int id, [Service] ClientesQueries clientesQueries, IResolverContext context) { // Access the request directly from the resolver context var queryRequest = context.Request; return await clientesQueries.GetClienteById(id, queryRequest); }
This is ideal if you only need the request within resolver workflows, as it eliminates the need for an interceptor altogether.
Option 3: Custom Query Execution Middleware
For more advanced scenarios, you can create a custom IQueryExecutionMiddleware to handle the request and pass it to downstream services. This gives you full control over the execution pipeline:
public class QueryRequestMiddleware : IQueryExecutionMiddleware { private readonly QueryExecutionDelegate _next; public QueryRequestMiddleware(QueryExecutionDelegate next) { _next = next; } public async ValueTask<IQueryResult> InvokeAsync(IQueryContext context) { // Access the request from the query context var queryRequest = context.Request; // You can inject services here and pass the request to them, // or store it in scoped context for later access var scopedContext = context.Services.GetRequiredService<IScopedContextProvider>(); scopedContext.Set("GraphQL_QueryRequest", queryRequest); return await _next(context); } } // Register the middleware in your startup services.AddGraphQLServer() .AddQueryType<Queries>() .AddMiddleware<QueryRequestMiddleware>();
This approach is best if you need to modify or inspect the request at specific points in the execution pipeline.
Comparison to Your Original Approach
Your initial method works, but the IScopedContextProvider approach is more maintainable and testable. Avoiding IHttpContextAccessor reduces tight coupling to ASP.NET Core, making your code more portable if you ever need to run your GraphQL layer outside a web context.
内容的提问来源于stack exchange,提问作者Lucas Phillip

