Use OutputCache with Entity GraphQl

36 views Asked by At

I'm trying to setup output caching using Entity GraphQl, but can't get it to work. It's a net8.0 project with EntityGraphQL.AspNet 5.1.1.

Here's my reduced Program.cs

using EntityGraphQL.AspNet;
using MedicalData.DataAccess;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddOutputCache();

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

builder.Services.AddMedicalDataDataAccess(builder.Configuration.GetSection("MedicalDataDataAccess").Bind);
builder.Services.AddGraphQLSchema<MedicalDataDbContext>();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseOutputCache();

app.MapGraphQL<MedicalDataDbContext>(
    configureEndpoint: endpointConventionBuilder =>
        endpointConventionBuilder.CacheOutput(outputCachePolicyBuilder =>
        {
            outputCachePolicyBuilder.VaryByValue(context =>
            {
                context.Request.EnableBuffering();

                using var bodyReader = new StreamReader(context.Request.Body, leaveOpen: true);
                var bodyContent = bodyReader.ReadToEndAsync()
                                            .Result
                                            .Replace(" ", "");

                // Reset the stream position to enable subsequent reads
                context.Request.Body.Position = 0;

                Console.WriteLine($"VaryByValue: {bodyContent}");

                return new KeyValuePair<string, string>("graphQl-requestBody", bodyContent);
            });

            outputCachePolicyBuilder.Expire(TimeSpan.FromHours(6));
        }));
app.MapGraphQLAltair();

app.MapControllers();

app.Run();

When executing the same graphql query multiple times, it is never being retrieved from the cache. The vary by value function is being executed each time, then the EF query:

VaryByValue: {"query":"{\narticle(id:3){\nupdatedOn\ndescription{\ncurrent\n}\n}\n}","variables":{},"operationName":null}
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[@__Value_id_Value_0='?' (DbType = Int64)], CommandType='Text', CommandTimeout='30']
      SELECT ...
      
VaryByValue: {"query":"{\narticle(id:3){\nupdatedOn\ndescription{\ncurrent\n}\n}\n}","variables":{},"operationName":null}
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[@__Value_id_Value_0='?' (DbType = Int64)], CommandType='Text', CommandTimeout='30']
      SELECT ...

I've added a log entry in a controller endpoint marked with [OutputCache(Duration = 60 * 60)]. If it is being called multiple times, only the first call enters, the subsequent ones come from the cache:

GetPaged ArticleResultDtos
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT COUNT(*)
      FROM [Articles] AS [a]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (3ms) [Parameters=[@__p_0='?' (DbType = Int32), @__p_1='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT ...

When using Redis, instead of the in memory cache for output caching, there is no entry written for graphql, for the controller call, there is one.

What am I missing to make the GraphQl output cache work?

0

There are 0 answers