In ASP.NET Core, output caching is achieved using a middleware. Enabling it is very straightforward.
Let’s open our Program
class and see how it’s done:
builder.Services.AddOutputCache(); builder.Services.AddEndpointsApiExplorer(); var app = builder.Build(); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); app.UseExceptionHandler(); app.UseOutputCache();
We start by calling the AddOutputCache()
method on our IServiceCollection
property. It registers the caching middleware. By default, only 200 OK
responses of GET
or HEAD
requests are cached. Any responses that deal with authenticated requests or set cookies aren’t cached. The whole URL and its parameters are used as the key of the cached response. Finally, the default expiration is set to one minute.
Next, we call the UseOutputCache()
method on our WebApplication
instance. This makes the caching middleware available for us to use but it will not cache responses until we’ve configured our endpoints to do so.
Note that, if you utilize the CORS middleware the UseOutputCache()
method must be called after the UseCors()
one. With APIs that use controllers, the UseOutputCache()
method should come after the UseRouting()
method.
We’ve enabled output caching, now it’s time to use it.
Let’s go to the Endpoints
folder and open the ProjectEndpoints
class:
group.MapGet("", async ( [AsParameters] ProjectRequestParameters requestParams, [FromServices] IServiceManager serviceManager, CancellationToken cancellationToken) => { ... }) .CacheOutput() .Produces<PagedList<ProjectResponse>>() .WithName(ProjectConstants.GetAllProjects); group.MapGet("{id:guid}", async ( [FromRoute] Guid id, [FromServices] IServiceManager serviceManager, CancellationToken cancellationToken) => { ... }) .CacheOutput() .Produces<ProjectResponse>() .Produces(StatusCodes.Status404NotFound) .WithName(ProjectConstants.GetProjectById) .MapToApiVersion(1); group.MapGet("{id:guid}", async ( [FromRoute] Guid id, [FromServices] IServiceManager serviceManager, CancellationToken cancellationToken) => { ... }) .CacheOutput() .Produces<ProjectResponse>() .Produces(StatusCodes.Status404NotFound) .WithName(ProjectConstants.GetProjectById + " v2") .MapToApiVersion(2);
We add a call to the CacheOutput()
method for all three of our GET
endpoints. This will enable caching based on the defaults mentioned earlier.
Let’s open Postman and get one page containing 5 projects by sending a GET
request:
curl --location 'https://localhost:5001/api/v1/projects?page=1&pageSize=5'
We get the expected 200 OK
response that took 59ms. The response headers are the same ones we saw in the previous module.
Now, let’s quickly resend the same request but before one minute has passed:
curl --location 'https://localhost:5001/api/v1/projects?page=1&pageSize=5'
We again get the 200 OK
response. This time it took only 5ms which is more than 10 times faster than the original request. Also, the versioning headers are missing, but we have a new header called Age
in their place. Its value also represents how long ago this response was cached.
No matter how many requests we send to the same endpoint in the one minute after the initial requests, we’ll get the response from the cache. As the whole URL is used for the cache key, if we change anything in the address, we’ll get a response that was not cached.