Back to: ASP.NET Core Web API Tutorials
Response Caching in ASP.NET Core Web API
In this article, I will discuss how to Implement Response Caching in ASP.NET Core Web API Applications with Examples. Please read our previous articles discussing how to Implement NCache in ASP.NET Core Web API Applications.
What is Response Caching?
Response caching is a technique used in web applications to store responses for some time, reducing the need to generate the same response multiple times. It helps improve performance, reduce server load, and enhance response times.
Response Caching in ASP.NET Core Web API is a mechanism that allows responses from the web server to be stored temporarily so that identical subsequent requests can be served quickly from the cache. Instead of processing the request fully each time (e.g., querying the database or performing heavy computation), the server returns a cached version of the response if available and still fresh. This results in improved performance, reduced server load, and faster response times.
Understanding Client and Proxy Caching
When we talk about Response Caching in ASP.NET Core Web API, we often refer to two types of caching:
Client-Side Caching:
Client-side caching means storing responses directly on the client device, such as in the browser’s local cache. When the client makes a subsequent request for the same resource, the cached response is used, reducing the need to contact the server again. The Cache-Control and Expires headers are key to instructing the client how long to keep and reuse the cached data. It is ideal for content specific to a user or when you want the browser to reduce repeat network calls.
Proxy-Server Caching:
Proxy-server caching involves caching at intermediary servers (such as a CDN or reverse proxy) between the client and the origin server. This allows multiple clients to benefit from a single cached response. If the proxy server has a fresh cached copy, it can deliver the response without reaching out to the origin server, thereby decreasing the load on the original server and saving server resources. It is ideal for shared content among many users (e.g., product listings, public news).
How Does Response Caching Work in ASP.NET Core Web API?
The following diagram explains how response caching works in the ASP.NET Core Web API Application.
Let us understand how Response Caching works in ASP.NET Core Web API Application with the help of the above diagram:
First Request
- Client Request: The client (e.g., a browser or mobile app) sends a request for a resource (e.g., GET /api/products). The request is routed through a proxy server (if present).
- Forwarding to Web Server: Since this is the first request, the proxy server has no cached response. It forwards the request to the web server.
- Caching the Response: The web server processes the request, generates a response, and includes a Cache-Control header to instruct the client and proxy to cache the response.
- Returning the Response: The proxy server caches the response and returns it to the client.
Subsequent Request
- Client Re-Request: When the client sends the same request again, the proxy server intercepts the request.
- Serving Cached Response: The proxy server recognizes it has a valid cached response and returns that instead of forwarding the request to the web server.
- Faster Response: The client receives the response more quickly, reducing the web server’s load.
Benefits of Response Caching:
- Reduces round-trip time (no need to hit the server repeatedly).
- Saves server processing power and bandwidth.
- Improves the user experience through faster response times.
How Do We Use Response Caching in ASP.NET Core Web API?
To implement response caching in an ASP.NET Core Web API:
- Enable Response Caching in the app by registering and using the Response Caching Middleware.
- Use the [ResponseCache] attribute on controllers or actions to set appropriate caching directives to specify how responses should be cached.
- Optionally customize caching with advanced configurations (e.g., VaryByHeader, VaryByQueryKeys, etc.).
- Set HTTP caching headers (Cache-Control, Vary, etc.) to inform clients and proxy servers how long and under what conditions they can reuse a cached response.
Implementing Response Caching in ASP.NET Core Web API:
Imagine we have an e-commerce application and need an endpoint that returns a list of products. These products are stored in an SQL Server database, and we use the Entity Framework Core Code First Approach to interact with the database. To optimize performance, we will implement response caching so that repeated requests for the same product data are served from the cache instead of hitting the application server and database every time.
Let’s proceed to understand how to implement Response Caching in an ASP.NET Core Web API application that interacts with a SQL Server database using the Entity Framework Core Code First Approach.
Create the Project and Install Packages
First, create a new ASP.NET Core Web API project with the name ResponseCachingDemo and then install the Following Packages, which are required for Entity Framework core to interact with the SQL Server database and manage database migration.
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Tools
You can install the above two packages using NuGet Package Manager Solutions or the Package Manager Console. To do so, open the Package Manager console and execute the following commands.
- Install-Package Microsoft.EntityFrameworkCore.SqlServer
- Install-Package Microsoft.EntityFrameworkCore.Tools
Create the Data Model and DbContext
First, create a folder named Models in the project root directory where we will create our Models and DbContext classes.
Create the Product Model:
Add a new class file named Product.cs within the Models folder and then copy and paste the following code.
using System.ComponentModel.DataAnnotations.Schema; namespace ResponseCachingDemo.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public string? Description { get; set; } [Column(TypeName = "decimal(8,2)")] public decimal Price { get; set; } public DateTime CreatedDate { get; set; } public DateTime ModifiedDate { get; set; } } }
Create the DbContext:
Next, add a class file named ApplicationDbContext.cs within the Models folder and copy and paste the following code. The OnModelCreating is overridden to configure the model and seed sample product data automatically for testing purposes.
using Microsoft.EntityFrameworkCore; namespace ResponseCachingDemo.Models { public class ApplicationDbContext : DbContext { // The options parameter will be injected by the framework (configured in Program.cs) public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } // Configure the model (including seed data) protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Seed data - this will insert initial rows into the Products table modelBuilder.Entity<Product>().HasData( new Product { Id = 1, Name = "Product A", Price = 10.0M, Description = "Product A Description", CreatedDate = DateTime.Today, ModifiedDate = DateTime.Today }, new Product { Id = 2, Name = "Product B", Price = 20.0M, Description = "Product B Description", CreatedDate = DateTime.Today, ModifiedDate = DateTime.Today }, new Product { Id = 3, Name = "Product C", Price = 30.0M, Description = "Product C Description", CreatedDate = DateTime.Today, ModifiedDate = DateTime.Today }, new Product { Id = 4, Name = "Product D", Price = 40.0M, Description = "Product D Description", CreatedDate = DateTime.Today, ModifiedDate = DateTime.Today }, new Product { Id = 5, Name = "Product E", Price = 50.0M, Description = "Product E Description", CreatedDate = DateTime.Today, ModifiedDate = DateTime.Today } ); } // Represents the Products table in the database public DbSet<Product> Products { get; set; } } }
Configure the connection string in appsettings.json:
Next, we need to include the connection string in the appsettings.json file. So, please modify the appsettings.json file as follows:
{ "ConnectionStrings": { "DefaultConnection": "Server=LAPTOP-6P5NK25R\\SQLSERVER2022DEV;Database=ProductsDB;Trusted_Connection=True;TrustServerCertificate=True;" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Register the DbContext and Response Caching in the Program.cs
Please modify the Program.cs class file as follows to register the DbContext and Response caching services to the built-in dependency injection container. Also, add the Response Caching Middleware components to the Request Processing pipeline.
using Microsoft.EntityFrameworkCore; using ResponseCachingDemo.Models; namespace ResponseCachingDemo { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Register the DbContext with SQL Server using the connection string from configuration builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // Register Response Caching services to enable caching functionality builder.Services.AddResponseCaching(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); // Add the Response Caching middleware to handle caching of HTTP responses app.UseResponseCaching(); app.MapControllers(); app.Run(); } } }
Code Explanation
- builder.Services.AddResponseCaching(): Registers the Response Caching service to enable response caching in ASP.NET Core Web API.
- app.UseResponseCaching(): Adds the Response Caching middleware to handle caching logic for HTTP requests and responses.
Generate and Apply Database Migration:
Open the Package Manager Console and execute the Add-Migration command to create a new Migration file. Then, execute the Update-Database command to apply the migration and update and sync the database with our models, as follows.
Once you execute the above command, it should create the ProductsDB database with the Products table, as shown in the below image:
How Do We Use ResponseCache Attribute in ASP.NET Core Web API?
To control caching behavior at the controller or action level, we need to use the [ResponseCache] attribute. The [ResponseCache] attribute in ASP.NET Core does not perform caching by itself. Instead, it sets the HTTP caching headers (like Cache-Control, Vary, etc.) and instructs clients and proxies on how to cache the responses. The following are the Key Properties of ResponseCache Attribute
Duration (int):
Specifies the number of seconds the response should be cached. This sets the max-age directive of the Cache-Control header. For example, Duration = 60 means the response is considered fresh for 60 seconds.
Location (ResponseCacheLocation Enum)
Defines where the response can be cached. The following are the possible values:
- Any: Cached by both client and proxy servers (default).
- Client: Cached only on the client side.
- None: Instructs clients to revalidate with the server before serving a cached response. Often sets Cache-Control: no-cache. Despite its name, no-cache can still store data; it must just be validated first.
NoStore (bool)
When set to true, add Cache-Control: no-store header. This prevents the response from being stored in any cache, which is beneficial for sensitive data. It takes precedence over other properties and ensures sensitive data is never cached.
VaryByHeader (string)
It instructs caches to store separate responses based on the value of the specified request header (e.g., User-Agent).
VaryByQueryKeys (string[])
Creates different cache entries based on the specified query string keys. This is useful when the response changes depending on query parameters.
Let us understand all the above Response Caching settings with a few examples.
Create the Products Controller
So, create an Empty API Controller named ProductsController within the Controllers folder and copy and paste the following code. The following code is self-explained, so please read the comment lines for a better understanding.
using Microsoft.AspNetCore.Mvc; using ResponseCachingDemo.Models; using Microsoft.EntityFrameworkCore; namespace ResponseCachingDemo.Controllers { [Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase { private readonly ApplicationDbContext _context; // Inject the DbContext via constructor dependency injection public ProductsController(ApplicationDbContext context) { _context = context; } // GET: api/Products // Caches the response for 60 seconds. // All requests share the same cached response. [ResponseCache(Duration = 60)] [HttpGet] public async Task<ActionResult<List<Product>>> GetProducts() { // Retrieve all products from the database var products = await _context.Products.ToListAsync(); // Artificial delay to simulate a performance difference (e.g., heavy processing) await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(products); } // GET: api/Products/5 // Caches the response for 120 seconds with separate cache entries based on the "id" query key. // So each product id has its own cached version. [ResponseCache(Duration = 120, VaryByQueryKeys = new[] { "id" })] [HttpGet("{id}")] public async Task<ActionResult<Product>> GetProduct(int id) { // Retrieve a single product by ID from the database var product = await _context.Products.FindAsync(id); if (product == null) { return NotFound(); } // Artificial delay for demonstration purposes await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(product); } // GET: api/Products/vary-query?sort=price // Caches different responses for 120 seconds based on the "sort" query parameter. [ResponseCache(Duration = 120, VaryByQueryKeys = new[] { "sort" })] [HttpGet("vary-query")] public async Task<ActionResult<List<Product>>> GetProductsVaryByQuery([FromQuery] string sort) { var products = await _context.Products.ToListAsync(); // Sort products based on the provided query parameter value if (!string.IsNullOrEmpty(sort)) { if (sort.Equals("price", StringComparison.OrdinalIgnoreCase)) { products = products.OrderBy(p => p.Price).ToList(); } else if (sort.Equals("name", StringComparison.OrdinalIgnoreCase)) { products = products.OrderBy(p => p.Name).ToList(); } } await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(products); } // GET: api/Products/anylocation // Response can be cached by both client and proxy servers (public). [ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any)] [HttpGet("anylocation")] public async Task<ActionResult<List<Product>>> GetProductsAnyLocation() { var products = await _context.Products.ToListAsync(); await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(products); } // GET: api/Products/clientlocation // Response is cached only on the client side (private). [ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)] [HttpGet("clientlocation")] public async Task<ActionResult<List<Product>>> GetProductsClientLocation() { var products = await _context.Products.ToListAsync(); await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(products); } // GET: api/Products/nolocation // Demonstrates conditional GET using the Last-Modified header. // The client sends an "If-None-Match" header, and if the data hasn't been updated since that time, // the server responds with a 304 Not Modified status. [ResponseCache(Duration = 60, Location = ResponseCacheLocation.None)] [HttpGet("nolocation/{id}")] public async Task<ActionResult<List<Product>>> GetProductsNoLocation(int id) { // Fetches the product by ID var product = await _context.Products.AsNoTracking().FirstOrDefaultAsync(prd => prd.Id == id); // Checks if the resource is null (not found) if (product == null) { // Returns a 404 Not Found response if the product is null return NotFound(); } // Converts the ModifiedDate property of the product to UTC time var lastModified = product.ModifiedDate.ToUniversalTime(); // Generates an ETag using the ticks of the ModifiedDate property var eTag = $"{lastModified.Ticks}"; // Checks if the request contains the If-None-Match header and if it matches the generated ETag if (Request.Headers.ContainsKey("If-None-Match") && Request.Headers["If-None-Match"].ToString() == eTag) { // Returns a 304 Not Modified status if the ETag matches return StatusCode(StatusCodes.Status304NotModified); } // Adds the ETag header to the response Response.Headers["ETag"] = eTag; // Returns a 200 OK status with the resource as the response body return Ok(product); } // GET: api/Products/nostore // Prevents the response from being stored in any cache. // NoStore = true => do not store this response anywhere [ResponseCache(NoStore = true)] [HttpGet("nostore")] public async Task<ActionResult<List<Product>>> GetProductsNoStore() { var products = await _context.Products.ToListAsync(); await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(products); } // GET: api/Products/varybyheader // Varies the cached response based on the "User-Agent" header. // VaryByHeader = "User-Agent" => caches different versions for different User-Agent values [ResponseCache(Duration = 60, VaryByHeader = "User-Agent")] [HttpGet("varybyheader")] public async Task<ActionResult<List<Product>>> GetProductsVaryByHeader() { var products = await _context.Products.ToListAsync(); await Task.Delay(TimeSpan.FromSeconds(3)); return Ok(products); } } }
Response Caching Header:
When the [ResponseCache] attribute is used, ASP.NET Core sets the Cache-Control headers:
- public: Response can be cached by any cache (client or proxy).
- private: Response can only be cached by the client. Proxy caches should not store it.
- max-age=<seconds>: Specifies how many seconds the response is considered fresh. For example, max-age=60 means the cached response is fresh for one minute.
- no-cache: Instructs clients to revalidate with the server before serving a cached response. (Despite its name, no-cache can still store data; it must be validated first.)
- no-store: This prevents the response from being cached anywhere. It is typically used when handling sensitive or confidential information.
Swagger Behavior:
When testing APIs, Swagger UI generally respects the HTTP caching headers sent by the server. If your application sends a response with Cache-Control set to private, max-age=300, Swagger UI will cache the response as instructed for the specified duration. Subsequent requests to the same endpoint (within the cache duration) might not hit the server if the cached response is deemed valid.
Postman Behavior:
However, Postman does not automatically cache responses like a typical web browser would, despite receiving the same caching headers. In Postman, whenever you hit the “Send” button, a new request is made to the server, ignoring any previous response cache headers. This is intentional, as Postman is designed for testing and development, where you often need to see live server responses without caching interference.
Testing Each Response Caching Endpoints
To effectively test the caching behavior of each action method, we can use tools like Swager, Fiddler, Postman, etc. The key is to inspect the HTTP response headers, particularly the Cache-Control header, to understand how caching is being handled.
GetProducts – api/Products
It demonstrates caching with Duration = 60 seconds.
Expected Behavior:
- First Request: Experiences a 3-second delay and caches the response.
- Subsequent Requests (within 60 seconds): Returns the cached response immediately.
- Response Headers: Cache-Control: public, max-age=60
How to Test: Use Swagger, Fiddler, or a browser to send a GET request. Check the response time and headers to confirm caching.
GetProduct – api/Products/{id}
It demonstrates caching with Duration = 120 seconds and VaryByQueryKeys = “id”.
Expected Behavior:
- First Request for a Specific ID: Experiences a delay and caches the response.
- Subsequent Requests (within 120 seconds): Returns the cached response.
- Different IDs: Each gets its own cache entry.
- Response Headers: Cache-Control: public, max-age=120
How to Test: Request a product by ID, then re-request the same ID. Change the ID to verify separate caching.
GetProductsAnyLocation – api/Products/anylocation
It demonstrates caching with Location = ResponseCacheLocation.Any.
Expected Behavior:
- Both the client and proxy cache the response.
- Response Headers: Cache-Control: public, max-age=60
How to Test: Send a GET request and verify the header shows public.
GetProductsClientLocation – api/Products/clientlocation
It demonstrates caching with Location = ResponseCacheLocation.Client.
Expected Behavior:
- The response is cached only on the client side.
- Response Headers: Cache-Control: private, max-age=60
How to Test: Check that proxy servers do not cache the response.
GetProductsNoLocation – api/Products/nolocation/1
It demonstrates caching with Location = ResponseCacheLocation.None.
Expected Behavior:
- The response is cached, but every time a client requests the resource, it must revalidate the cached response with the server before it can be used.
- Response Headers: Cache-Control: no-cache
How to Test: Each request will be accompanied by a revalidation check with the server, ensuring that the client always verifies its freshness even though the response is stored.
How Does It Work Internally?
The client verifies the freshness of a cached response by sending a conditional GET request to the server. This request includes headers that compare the stored copy with the server’s current version:
- ETag: If the server provided an ETag (a unique identifier for the resource’s version), the client will include an If-None-Match header with the ETag value. The server then compares this with the current ETag. If they match, the resource hasn’t changed, and the server returns a 304 Not Modified response.
These mechanisms ensure that even though the response may be cached locally, the client continuously checks with the server to determine if the cached data is still fresh.
GetProductsNoStore – api/Products/nostore
It demonstrates caching with NoStore = true.
Expected Behavior:
- The response is not stored in any cache.
- Response Headers: Cache-Control: no-store
How to Test: Confirm that neither the client nor the proxy caches the response.
GetProductsVaryByHeader – api/Products/varybyheader
It demonstrates caching with VaryByHeader = “User-Agent”.
Expected Behavior:
The response varies based on the User-Agent header.
Response Headers:
- Cache-Control: public, max-age=60
- Vary: User-Agent
How to Test: Use different User-Agent request values to see distinct cached responses.
Custom Cache Profile with Response Caching
In ASP.NET Core Web API, when multiple actions or controllers share the same caching requirements, we can centralize these settings in a named cache profile. This avoids duplicating attributes (like Duration=60, Location=Any) across multiple methods.
These profiles are defined in the Program.cs class file, and can then be referenced by its name in controllers. Let us understand this with an example. First, modify the Program class as follows:
using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using ResponseCachingDemo.Models; namespace ResponseCachingDemo { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Register the DbContext with SQL Server using the connection string from configuration builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // Register Response Caching services to enable caching functionality builder.Services.AddResponseCaching(); // Configure controllers and add a custom cache profile. builder.Services.AddControllers(options => { // Creating Custom Cache Profiles // "Default60" cache profile: // cache for 60 seconds and allow caching anywhere. options.CacheProfiles.Add("Default60", new CacheProfile() { Duration = 60, Location = ResponseCacheLocation.Any }); }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); // Add the Response Caching middleware to handle caching of HTTP responses app.UseResponseCaching(); app.MapControllers(); app.Run(); } } }
Here, we have configured one cache profile (Default60), as shown in the below image:
Using Cache Profile in Response Cache Attribute:
Once you define the Cache Profiles, they can be used within controller actions by referring to the profile name using the CacheProfileName property of the ResponseCache attribute. So, modify the ProductsController as follows. We have specified the Default60 Cache profile within the GetProducts Action method.
using Microsoft.AspNetCore.Mvc; using ResponseCachingDemo.Models; using Microsoft.EntityFrameworkCore; namespace ResponseCachingDemo.Controllers { [Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase { private readonly ApplicationDbContext _context; public ProductsController(ApplicationDbContext context) { _context = context; } // GET: api/Products // Apply the "Default60" cache profile defined in Program.cs. [ResponseCache(CacheProfileName = "Default60")] [HttpGet] public async Task<ActionResult<List<Product>>> GetProducts() { // Retrieve all products from the database var products = await _context.Products.ToListAsync(); return Ok(products); } } }
When Should We Use Response Caching in ASP.NET Core Web API?
By implementing response caching in the ASP.NET Core Web API application, we can significantly improve performance, reduce server load, and enhance the user experience. Response Caching is suitable for scenarios such as:
- Data that Rarely Changes: When data is read frequently but does not change often and does not need to be refreshed on every request (e.g., product lists, static resources).
- Response Reusability: When responses can be reused for a certain period, the application server and database load are reduced, and response time is improved.
- Repeated Requests: When multiple clients request the same resource, cached responses reduce redundant processing.
However, consider the following:
Avoid caching highly dynamic or sensitive data (e.g., user-specific data, rapidly changing data). If underlying data changes frequently, it might serve outdated information if you do not configure cache duration carefully.
What Is a Proxy Server?
A proxy server is an intermediary server that sits between the client (such as a browser) and the web server (ASP.NET Core application). It forwards client requests to the server and then returns the server’s response to the client. The following are the Common Examples of Proxy Server:
- Reverse Proxies: Tools like Nginx, Apache, or IIS ARR are configured in front of your application.
- Content Delivery Networks (CDNs): Services such as Cloudflare, Akamai, or Azure Front Door that cache static and dynamic content closer to your users.
When and How Is a Proxy Server Created?
An ASP.NET Core Web API application does not automatically create or manage a proxy server.
- Infrastructure Setup: Typically, your DevOps or IT team (or cloud provider) sets up the proxy server. For example, if you deploy your ASP.NET Core app behind Nginx or IIS with ARR (Application Request Routing), the proxy server is installed and configured outside of your application code.
- Configuration: Once the proxy is running, you configure where it should forward requests. For instance, if the proxy listens on https://api.mycompany.com, you might configure it to forward incoming requests to http://localhost:5000 (where your ASP.NET Core app runs). During configuration, you can enable caching, compression, load balancing, etc.
- Deployment: When you deploy your Web API to production (or any hosted environment), a proxy server (like a load balancer or a CDN) might already be in front of it. If that proxy is configured to respect and store HTTP cache headers, it will automatically handle caching for your responses.
How Does a Proxy Server Handle Response Caching?
Reading HTTP Headers:
When your ASP.NET Core API sends responses with caching headers (e.g., Cache-Control: public, max-age=60), the proxy server can inspect these headers and decide:
- Should I cache this response? (Does the public allow it? Is no-store or private specified?)
- How long should I keep it? (Is there a max-age directive, e.g., 60 seconds?)
- Does the request method matter? (Typically, GET responses are cacheable; POST, PUT, and DELETE are usually not.)
Storing the Response
If the headers permit, the proxy server stores the response in its local cache (memory, disk, or a distributed cache system). It keys the response by the URL (and sometimes other Vary directives like query parameters or headers).
Serving Cached Content
When a subsequent request for the same resource (same URL, same relevant headers) arrives:
- Proxy Checks Expiry: The proxy checks if it has a fresh copy in its cache (i.e., one that has not expired according to max age).
- Returns Cached Content: If the cached content is valid, it returns it immediately—without contacting the origin ASP.NET Core server.
- Refresh on Expiry: If the content expires (or headers require revalidation), the proxy may contact the origin server to refresh or validate the cache entry.
Response Caching in ASP.NET Core Web API can significantly improve application performance and scalability. Using the [ResponseCache] attribute, we can set caching rules, controlling how clients and proxies store and reuse responses. Testing your caching strategy to ensure it meets both performance goals and data consistency requirements is always important.
In the next article, I will start Security in ASP.NET Core Web API Applications with Examples. In this article, I explain How to Implement Response Caching in ASP.NET Core Web API Application with Examples. I hope you enjoy this article, How to Implement Response Caching in ASP.NET Core Web API.