Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

ASP.NET Core output caching can make repeat requests far cheaper and faster by returning a previously generated HTTP response instead of running the endpoint every time. Enable it with AddOutputCache and UseOutputCache, then opt individual endpoints into caching with CacheOutput or [OutputCache]. The safe design depends on explicit expiration, a cache key that represents every input affecting the response, and strict separation between public and user-specific data.

What ASP.NET Core output caching does

Output caching stores the complete HTTP response produced by an ASP.NET Core endpoint. On a later request that matches the cache key and policy, the middleware can return the stored status code, headers and body without invoking the handler, controller action, view or downstream work again.

The middleware supports Minimal APIs, controller-based Web APIs, MVC and Razor Pages. It is different from response compression: compression reduces the size of a response, while output caching avoids regenerating the response at all. It is also different from data caching, where an application stores a database result and still executes endpoint code to assemble a response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Output caching is most useful when many requests ask for the same representation and the underlying data can tolerate a defined amount of staleness. Product catalogs, public reference data, documentation pages and other broadly shared GET responses are common candidates. A profile, account balance or permission-sensitive response normally needs exclusion or carefully designed variation instead.

#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter | 4Pack Type C Female to A Male Cable Converter for Apple Duo 17 16 15 14 Plus,iWatch Watch 12 11 10,iPad 9 8 Air,Airpods 5 4
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

Enable output caching in an ASP.NET Core application

  1. Register the service. Add builder.Services.AddOutputCache(); while configuring services.
  2. Add the middleware. Call app.UseOutputCache(); after building the application.
  3. Opt endpoints in. Add .CacheOutput() to a Minimal API route, apply [OutputCache] to a controller action, or select a named policy.
  4. Run a request twice. The first request populates the cache; a matching later request can be served from the stored response while the entry remains valid.
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOutputCache();

var app = builder.Build();

app.UseOutputCache();

app.MapGet("/cached", () =>
{
    return Results.Ok(new { generatedAt = DateTimeOffset.UtcNow });
}).CacheOutput();

app.Run();

Registering the service and middleware only makes output caching available. An endpoint still needs caching configuration; otherwise it is not automatically cached.

Use named policies for repeatable rules

A named policy keeps expiration and variation rules in one place. Minimal API endpoints select it with CacheOutput("PolicyName"). Controller actions select the same policy with [OutputCache(PolicyName = "PolicyName")].

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("Products", policy =>
        policy.Expire(TimeSpan.FromSeconds(30)));
});

app.MapGet("/products", GetProducts)
   .CacheOutput("Products");
[ApiController]
[Route("api/products")]
public sealed class ProductsController : ControllerBase
{
    [HttpGet]
    [OutputCache(PolicyName = "Products")]
    public IActionResult Get() => Ok(/* representation */);
}

Use a base policy when most cacheable endpoints share a conservative default, then add named policies where an endpoint needs a different lifetime or key. A policy that does not specify an expiration uses the documented default of one minute.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Understand the built-in safety boundaries

By default, ASP.NET Core output caching stores only successful HTTP 200 responses to GET or HEAD requests. Responses that set cookies are excluded, as are responses to authenticated requests. These defaults reduce the chance of storing a response that is not safe to share.

Those checks are safeguards, not a substitute for reviewing every endpoint. An anonymous endpoint can still reveal data that should not be shared, and a response can vary on a header or query value that is not represented in its key. Treat authorization, tenant, locale, feature flags and other response-driving inputs as part of the cache design.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter | USB C Dongle with 90W Max Power Delivery, 3×5Gbps USB A Data Ports, for MacBook, Dell, and More (Charger Not Included)
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Place the middleware after authentication and authorization

In an application that uses authentication or authorization, run output caching after both systems have executed:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseOutputCache();

app.MapControllers();

This ordering ensures authorization runs before a cached response can be returned. Placing output caching before authorization can allow a response generated for one request context to be served without the intended authorization checks.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Exclude data that is inherently personal or sensitive

  • User dashboards, account details and private messages should generally not be shared through a public response cache.
  • Permission-sensitive data must either remain uncached or vary on every permission input that changes the representation.
  • Rapidly changing values, such as a live status feed, need a short lifetime or a different delivery design.
  • Responses that set cookies are excluded by the default behavior; do not work around that check without understanding the privacy consequence.

Set expiration based on acceptable staleness

Expiration is a business rule, not merely a performance setting. Ask how old a response may be before it becomes misleading, then choose a duration that stays inside that limit. A ten-second product price window and a several-hour documentation window have very different correctness requirements.

Policy approach Example duration When it fits Main trade-off
Base policy 10 seconds in the example below Most cacheable endpoints need a short, predictable default Endpoints with different freshness needs require an override
Named endpoint policy 30 seconds for products in the example below A route has a known tolerance for staleness More policies need documentation and review
No explicit expiration One minute documented default Only when the default is acceptable The lifetime may be longer or shorter than the endpoint’s actual requirement
builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(policy =>
        policy.Expire(TimeSpan.FromSeconds(10)));

    options.AddPolicy("Products", policy =>
        policy.Expire(TimeSpan.FromSeconds(30)));
});

Expiration alone cannot provide immediate freshness after a write. If a product changes, a thirty-second policy can continue serving the previous representation until that interval ends unless the application evicts the related entry.

Design the cache key so representations cannot collide

The default output-cache key includes the request scheme, host, port, path and query string. This is a useful starting point for routes whose response is fully determined by those values. It is not enough when a response changes because of a header, route interpretation, host-specific behavior or an application-defined value.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter | 85W Max PD, 2 USB 3.0 & 1 USBC Data Ports, SD/TF Card Reader, for Laptops/Mac and Other Type C Devices (Charger Not Included)
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Every input that changes the representation must be represented in the key. If an input does not change the response, varying on it only creates unnecessary entries and lowers the hit rate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Vary by only the query parameters that matter

Use SetVaryByQuery when one or more query values select the representation. This is preferable to treating every incidental query parameter as meaningful.

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("Culture", policy =>
        policy.SetVaryByQuery("culture"));
});

For a route such as /catalog?culture=en-US, the policy creates separate representations for different culture values. If the handler ignores a query parameter, do not vary on it; otherwise identical content occupies multiple cache entries.

Use headers, route values and hosts deliberately

  • SetVaryByHeader separates responses that change according to a request header, such as a representation or language choice.
  • SetVaryByRouteValue separates route parameters that influence the body or metadata.
  • SetVaryByHost is appropriate when the same path has different representations for different host names.
  • Case-sensitive path configuration is available when two paths that differ only by case must be treated as distinct.
  • VaryByValue supports a custom value when the response depends on application state that is not directly represented by a query, header, route value or host.

Under-varying is a correctness bug: one request can receive another request’s representation. Over-varying is a capacity and performance problem: memory usage grows while repeated requests stop sharing entries. Document the exact inputs used by the handler and map each one to the narrowest appropriate variation rule.

Invalidate related responses with tags

Time-based expiration is simple, but it cannot remove an entry immediately after a write. Tags let several entries be evicted as a group. Assign a common tag to related endpoints or a route group, then evict that tag after a successful update.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray | Data transfer & Fast charging for MacBook, iPhone 17/16/15, iPad, Samsung Galaxy, Apple Watch
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
app.MapPost("/purge/{tag}", async (IOutputCacheStore store, string tag) =>
{
    await store.EvictByTagAsync(tag, default);
    return Results.NoContent();
});

A products policy can attach a products tag, while a broader operational tag can support a whole-cache eviction workflow. Keep purge operations behind appropriate authorization and operational controls; an unprotected purge endpoint can be abused to erase the cache continuously and create avoidable origin load.

Eviction should follow the write’s outcome. Purging before a database transaction commits can leave the cache empty even when the write later fails, while purging only after a successful commit avoids advertising a change that did not persist.

Prevent a cache stampede during misses

When an entry expires, many concurrent requests can arrive at once. If every request regenerates the response independently, the origin may experience a thundering herd precisely when a popular entry disappears.

Resource locking is enabled by default. Microsoft’s ASP.NET Core output-caching documentation states: “By default, resource locking is enabled to mitigate the risk of cache stampede and thundering herd.” With locking enabled, concurrent requests for the same missing resource can coordinate so that one generation populates the entry while others wait for the result.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

You can disable locking with SetLocking(false), but do so only when measured concurrency behavior and the endpoint’s cost justify it. No-lock operation can reduce coordination overhead for a very cheap handler, yet it permits duplicate work during a miss and can overload a slow downstream service.

Best Value
Sale
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display | 85W Max PD, 1 Powered USB-C 5Gbps & 2 Powered USB-A 3.0 5Gbps Data Ports, for MacBook Pro, MacBook Air, Dell and More (Black)
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("LowCost", policy =>
        policy.Expire(TimeSpan.FromSeconds(5))
              .SetLocking(false));
});

Choose in-process or distributed storage

Output-cache storage determines which requests can reuse an entry. In-process storage is local to one application instance. It is straightforward and fast, but each instance has its own entries; a load balancer can send successive requests to servers with different cache states.

Microsoft also documents a StackExchange.Redis output-cache package for distributed storage. A distributed store allows instances to share entries, which is useful in a scaled-out deployment, but introduces network latency, availability dependencies, serialization considerations and package-version compatibility work.

Storage topology Strengths Costs and risks Best fit
In-process No extra network hop; simple deployment; each node can serve its own hot entries Entries are not shared; restarts and scale-out create cold caches on individual nodes Single-instance services or workloads where local warmth is sufficient
Distributed store Shared entries across application instances; more consistent reuse behind a load balancer Requires an additional service, network calls, capacity planning and verified package compatibility Multi-instance deployments where shared cache state is valuable

Verify the output-cache package and runtime versions together before deployment. A distributed design does not remove the need for correct variation or invalidation; it only changes where entries are stored.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Decide which API responses belong in the cache

Good candidates

  • Public GET endpoints with repeated requests for identical representations.
  • Responses whose source data changes less frequently than the selected expiration window.
  • Expensive read operations where a shared response can remove database, template or downstream-service work.
  • Reference and catalog data that can be grouped under a predictable invalidation tag.

Use caution or exclude

  • Authenticated responses when the body depends on the caller.
  • Tenant-specific data unless tenant identity is represented safely in the key and authorization still runs first.
  • Responses affected by permissions, feature flags, experiments or opaque headers that have not been mapped to variation.
  • Endpoints with side effects or methods other than GET and HEAD, which are outside the default cacheable set.

Start with one public, read-only endpoint. Confirm its representation is identical for every request sharing the intended key, then expand the policy to related routes.

Build a complete products endpoint policy

The following pattern combines a named lifetime with query variation. It assumes that the product representation changes with culture and that the endpoint is public and read-only.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("Products", policy =>
        policy.Expire(TimeSpan.FromSeconds(30))
              .SetVaryByQuery("culture"));
});

var app = builder.Build();

app.UseOutputCache();

app.MapGet("/products", (string? culture) =>
{
    // Load and format products for the requested culture.
    return Results.Ok(new { culture, items = Array.Empty<object>() });
}).CacheOutput("Products");

app.Run();

After a product write succeeds, evict the products tag if the policy assigns one. If the representation also changes by a header, route value or custom application state, add the corresponding variation before enabling the endpoint in production.

Test that caching is correct, not merely faster

  1. Verify the first request. Confirm the handler runs and returns the expected status, headers and body.
  2. Repeat the identical request. Confirm the response remains correct while the entry is valid and that the handler is not doing unnecessary repeated work.
  3. Change each response-driving input. Test every relevant query value, header, route value, host and custom variation to ensure it receives the correct representation.
  4. Test authorization contexts. Check anonymous, authenticated and unauthorized requests separately, including a user who must not see another user’s data.
  5. Test expiration. Wait beyond the configured lifetime and verify that a fresh response is generated.
  6. Test invalidation. Perform a successful write, evict its tag and confirm the next read reflects the committed value.
  7. Test concurrency. Expire a popular entry and send concurrent misses to observe whether locking protects the origin as intended.

Do not infer a cache hit solely from a fast client-side timing result. Instrument the handler or use application metrics so a test can distinguish a cached response from a fast origin response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Measure the benefits and the costs

The official documentation does not publish a universal benchmark for latency, throughput or CPU reduction. Results depend on response size, endpoint work, data-store latency, traffic shape, cache lifetime, storage topology and deployment size. Treat any fixed percentage promise as unsupported until your own workload demonstrates it.

Track these signals in the target deployment:

  • Hit and miss rates: show whether the chosen key and expiration let requests share entries.
  • Endpoint latency: compare cache hits, misses and uncached requests separately.
  • Origin work: database calls, downstream requests, CPU time and allocations saved by hits.
  • Memory or distributed-store usage: watch growth as variation creates more representations.
  • Stale-response impact: record incidents where a valid cached response was older than the business could tolerate.
  • Eviction and lock contention: identify purge storms or popular keys that create waiters during regeneration.

Troubleshoot common output-cache failures

Every request still executes the handler

  • Check that AddOutputCache is registered and UseOutputCache is in the request pipeline.
  • Confirm the endpoint is opted in with CacheOutput, a named policy or [OutputCache].
  • Verify the request is GET or HEAD and the response status is 200.
  • Look for a response cookie or an authenticated request, both excluded by default.
  • Check that the request is not varying on a value that changes every time.

A caller receives the wrong representation

  • List every query, header, route, host and custom value read by the handler.
  • Add the missing input to the cache key with the appropriate variation control.
  • Review tenant and authorization boundaries; disabling a safety check is not a fix for an incomplete key.

Fresh data appears late

  • Shorten the policy’s expiration to the allowed staleness window.
  • Evict the relevant tag after a successful write.
  • Check whether a distributed store contains entries that another instance did not purge because the deployment is using separate stores.

Origin load spikes when popular entries expire

  • Keep the default resource locking unless measurements show a clear reason to change it.
  • Inspect whether many keys expire simultaneously and adjust policy durations if appropriate.
  • Review endpoint cost and downstream capacity before selecting SetLocking(false).

Production checklist

  • Register AddOutputCache and place UseOutputCache correctly in the pipeline.
  • Opt in only endpoints whose responses can be safely shared.
  • Run output caching after authentication and authorization.
  • Set an explicit expiration for each policy whose freshness requirement differs from the one-minute default.
  • Map every response-driving input to the cache key and avoid irrelevant variation.
  • Use tags for write-triggered invalidation and protect purge operations.
  • Retain resource locking unless measured workload behavior supports disabling it.
  • Choose in-process or distributed storage according to deployment topology.
  • Test anonymous, authenticated, unauthorized, varied and concurrent requests.
  • Monitor hit rate, latency, origin work, memory, eviction, lock contention and stale-response impact.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.