mvp24hours-dotnet-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mvp24hours-dotnet-mcp might be problematic. Click here for more details.
- package/CONTRIBUTING.md +217 -0
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1454 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/ai-implementation.d.ts +28 -0
- package/dist/tools/ai-implementation.d.ts.map +1 -0
- package/dist/tools/ai-implementation.js +1251 -0
- package/dist/tools/ai-implementation.js.map +1 -0
- package/dist/tools/architecture-advisor.d.ts +42 -0
- package/dist/tools/architecture-advisor.d.ts.map +1 -0
- package/dist/tools/architecture-advisor.js +442 -0
- package/dist/tools/architecture-advisor.js.map +1 -0
- package/dist/tools/containerization-patterns.d.ts +18 -0
- package/dist/tools/containerization-patterns.d.ts.map +1 -0
- package/dist/tools/containerization-patterns.js +819 -0
- package/dist/tools/containerization-patterns.js.map +1 -0
- package/dist/tools/core-patterns.d.ts +18 -0
- package/dist/tools/core-patterns.d.ts.map +1 -0
- package/dist/tools/core-patterns.js +1039 -0
- package/dist/tools/core-patterns.js.map +1 -0
- package/dist/tools/cqrs-guide.d.ts +18 -0
- package/dist/tools/cqrs-guide.d.ts.map +1 -0
- package/dist/tools/cqrs-guide.js +2777 -0
- package/dist/tools/cqrs-guide.js.map +1 -0
- package/dist/tools/database-advisor.d.ts +39 -0
- package/dist/tools/database-advisor.d.ts.map +1 -0
- package/dist/tools/database-advisor.js +598 -0
- package/dist/tools/database-advisor.js.map +1 -0
- package/dist/tools/get-started.d.ts +20 -0
- package/dist/tools/get-started.d.ts.map +1 -0
- package/dist/tools/get-started.js +254 -0
- package/dist/tools/get-started.js.map +1 -0
- package/dist/tools/get-template.d.ts +17 -0
- package/dist/tools/get-template.d.ts.map +1 -0
- package/dist/tools/get-template.js +605 -0
- package/dist/tools/get-template.js.map +1 -0
- package/dist/tools/infrastructure-guide.d.ts +18 -0
- package/dist/tools/infrastructure-guide.d.ts.map +1 -0
- package/dist/tools/infrastructure-guide.js +1078 -0
- package/dist/tools/infrastructure-guide.js.map +1 -0
- package/dist/tools/messaging-patterns.d.ts +18 -0
- package/dist/tools/messaging-patterns.d.ts.map +1 -0
- package/dist/tools/messaging-patterns.js +718 -0
- package/dist/tools/messaging-patterns.js.map +1 -0
- package/dist/tools/modernization-guide.d.ts +23 -0
- package/dist/tools/modernization-guide.d.ts.map +1 -0
- package/dist/tools/modernization-guide.js +1072 -0
- package/dist/tools/modernization-guide.js.map +1 -0
- package/dist/tools/observability-setup.d.ts +23 -0
- package/dist/tools/observability-setup.d.ts.map +1 -0
- package/dist/tools/observability-setup.js +592 -0
- package/dist/tools/observability-setup.js.map +1 -0
- package/dist/tools/reference-guide.d.ts +18 -0
- package/dist/tools/reference-guide.d.ts.map +1 -0
- package/dist/tools/reference-guide.js +890 -0
- package/dist/tools/reference-guide.js.map +1 -0
- package/dist/tools/security-patterns.d.ts +18 -0
- package/dist/tools/security-patterns.d.ts.map +1 -0
- package/dist/tools/security-patterns.js +898 -0
- package/dist/tools/security-patterns.js.map +1 -0
- package/dist/tools/testing-patterns.d.ts +18 -0
- package/dist/tools/testing-patterns.d.ts.map +1 -0
- package/dist/tools/testing-patterns.js +1151 -0
- package/dist/tools/testing-patterns.js.map +1 -0
- package/dist/utils/doc-loader.d.ts +28 -0
- package/dist/utils/doc-loader.d.ts.map +1 -0
- package/dist/utils/doc-loader.js +88 -0
- package/dist/utils/doc-loader.js.map +1 -0
- package/docs/ai-context/ai-decision-matrix.md +216 -0
- package/docs/ai-context/ai-implementation-index.md +333 -0
- package/docs/ai-context/api-versioning-patterns.md +597 -0
- package/docs/ai-context/architecture-templates.md +794 -0
- package/docs/ai-context/containerization-patterns.md +633 -0
- package/docs/ai-context/database-patterns.md +575 -0
- package/docs/ai-context/decision-matrix.md +329 -0
- package/docs/ai-context/error-handling-patterns.md +727 -0
- package/docs/ai-context/home.md +298 -0
- package/docs/ai-context/messaging-patterns.md +547 -0
- package/docs/ai-context/modernization-patterns.md +756 -0
- package/docs/ai-context/observability-patterns.md +594 -0
- package/docs/ai-context/project-structure.md +264 -0
- package/docs/ai-context/security-patterns.md +662 -0
- package/docs/ai-context/structure-complex-nlayers.md +982 -0
- package/docs/ai-context/structure-minimal-api.md +668 -0
- package/docs/ai-context/structure-simple-nlayers.md +754 -0
- package/docs/ai-context/template-agent-framework-basic.md +1159 -0
- package/docs/ai-context/template-agent-framework-middleware.md +519 -0
- package/docs/ai-context/template-agent-framework-multi-agent.md +1187 -0
- package/docs/ai-context/template-agent-framework-workflows.md +1234 -0
- package/docs/ai-context/template-clean-architecture.md +858 -0
- package/docs/ai-context/template-cqrs.md +938 -0
- package/docs/ai-context/template-ddd.md +1053 -0
- package/docs/ai-context/template-event-driven.md +884 -0
- package/docs/ai-context/template-hexagonal.md +922 -0
- package/docs/ai-context/template-microservices.md +788 -0
- package/docs/ai-context/template-sk-chat-completion.md +816 -0
- package/docs/ai-context/template-sk-planners.md +859 -0
- package/docs/ai-context/template-sk-plugins.md +793 -0
- package/docs/ai-context/template-sk-rag-basic.md +890 -0
- package/docs/ai-context/template-skg-chain-of-thought.md +981 -0
- package/docs/ai-context/template-skg-chatbot-memory.md +785 -0
- package/docs/ai-context/template-skg-checkpointing.md +1314 -0
- package/docs/ai-context/template-skg-document-pipeline.md +1110 -0
- package/docs/ai-context/template-skg-graph-executor.md +777 -0
- package/docs/ai-context/template-skg-human-in-loop.md +1179 -0
- package/docs/ai-context/template-skg-multi-agent.md +901 -0
- package/docs/ai-context/template-skg-observability.md +1020 -0
- package/docs/ai-context/template-skg-react-agent.md +742 -0
- package/docs/ai-context/template-skg-streaming.md +930 -0
- package/docs/ai-context/testing-patterns.md +715 -0
- package/docs/application-services.md +883 -0
- package/docs/broker-advanced.md +738 -0
- package/docs/broker.md +188 -0
- package/docs/caching-advanced.md +666 -0
- package/docs/core/entity-interfaces.md +412 -0
- package/docs/core/exceptions.md +439 -0
- package/docs/core/functional-patterns.md +382 -0
- package/docs/core/guard-clauses.md +385 -0
- package/docs/core/home.md +109 -0
- package/docs/core/infrastructure-abstractions.md +386 -0
- package/docs/core/smart-enums.md +327 -0
- package/docs/core/strongly-typed-ids.md +352 -0
- package/docs/core/value-objects.md +356 -0
- package/docs/cqrs/api-reference.md +433 -0
- package/docs/cqrs/behaviors.md +215 -0
- package/docs/cqrs/best-practices.md +300 -0
- package/docs/cqrs/commands.md +267 -0
- package/docs/cqrs/concepts-comparison.md +208 -0
- package/docs/cqrs/domain-events.md +244 -0
- package/docs/cqrs/event-sourcing/aggregate.md +303 -0
- package/docs/cqrs/event-sourcing/event-store.md +292 -0
- package/docs/cqrs/event-sourcing/home.md +182 -0
- package/docs/cqrs/event-sourcing/projections.md +312 -0
- package/docs/cqrs/event-sourcing/snapshots.md +316 -0
- package/docs/cqrs/extensibility.md +473 -0
- package/docs/cqrs/getting-started.md +163 -0
- package/docs/cqrs/home.md +81 -0
- package/docs/cqrs/integration-caching.md +238 -0
- package/docs/cqrs/integration-events.md +257 -0
- package/docs/cqrs/integration-rabbitmq.md +304 -0
- package/docs/cqrs/integration-repository.md +235 -0
- package/docs/cqrs/integration-unitofwork.md +224 -0
- package/docs/cqrs/mediator.md +232 -0
- package/docs/cqrs/migration-mediatr.md +304 -0
- package/docs/cqrs/multi-tenancy.md +473 -0
- package/docs/cqrs/notifications.md +234 -0
- package/docs/cqrs/observability/audit.md +300 -0
- package/docs/cqrs/observability/telemetry.md +290 -0
- package/docs/cqrs/observability/tracing.md +284 -0
- package/docs/cqrs/queries.md +263 -0
- package/docs/cqrs/resilience/circuit-breaker.md +341 -0
- package/docs/cqrs/resilience/idempotency.md +200 -0
- package/docs/cqrs/resilience/inbox-outbox.md +450 -0
- package/docs/cqrs/resilience/retry.md +238 -0
- package/docs/cqrs/saga/compensation.md +311 -0
- package/docs/cqrs/saga/home.md +199 -0
- package/docs/cqrs/saga/implementation.md +422 -0
- package/docs/cqrs/scheduled-commands.md +537 -0
- package/docs/cqrs/specifications.md +580 -0
- package/docs/cqrs/validation-behavior.md +287 -0
- package/docs/cronjob-advanced.md +921 -0
- package/docs/cronjob-observability.md +369 -0
- package/docs/cronjob-resilience.md +378 -0
- package/docs/cronjob.md +343 -0
- package/docs/database/efcore-advanced.md +765 -0
- package/docs/database/mongodb-advanced.md +716 -0
- package/docs/database/nosql.md +226 -0
- package/docs/database/relational.md +145 -0
- package/docs/database/use-context.md +97 -0
- package/docs/database/use-entity.md +72 -0
- package/docs/database/use-repository.md +120 -0
- package/docs/database/use-service.md +58 -0
- package/docs/database/use-unitofwork.md +34 -0
- package/docs/documentation.md +186 -0
- package/docs/getting-started.md +163 -0
- package/docs/home.md +76 -0
- package/docs/index.md +175 -0
- package/docs/logging.md +301 -0
- package/docs/mapping.md +163 -0
- package/docs/migration.md +411 -0
- package/docs/modernization/aspire.md +393 -0
- package/docs/modernization/channels.md +440 -0
- package/docs/modernization/dotnet9-features.md +281 -0
- package/docs/modernization/generic-resilience.md +373 -0
- package/docs/modernization/http-resilience.md +250 -0
- package/docs/modernization/hybrid-cache.md +431 -0
- package/docs/modernization/keyed-services.md +383 -0
- package/docs/modernization/migration-guide.md +657 -0
- package/docs/modernization/minimal-apis.md +407 -0
- package/docs/modernization/native-openapi.md +426 -0
- package/docs/modernization/options-configuration.md +404 -0
- package/docs/modernization/output-caching.md +454 -0
- package/docs/modernization/periodic-timer.md +315 -0
- package/docs/modernization/problem-details.md +432 -0
- package/docs/modernization/rate-limiting.md +385 -0
- package/docs/modernization/source-generators.md +219 -0
- package/docs/modernization/time-provider.md +303 -0
- package/docs/observability/exporters.md +556 -0
- package/docs/observability/home.md +186 -0
- package/docs/observability/logging.md +589 -0
- package/docs/observability/metrics.md +504 -0
- package/docs/observability/migration.md +337 -0
- package/docs/observability/tracing.md +453 -0
- package/docs/pipeline.md +383 -0
- package/docs/release.md +253 -0
- package/docs/specification.md +130 -0
- package/docs/telemetry.md +189 -0
- package/docs/validation.md +205 -0
- package/docs/webapi-advanced.md +1188 -0
- package/docs/webapi.md +401 -0
- package/package.json +68 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# Output Caching - ASP.NET Core Native Server-Side Caching
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
**Output Caching** is a server-side caching mechanism introduced in .NET 7 that stores complete HTTP responses on the server and serves them directly without re-executing endpoint logic. Unlike Response Caching (which relies on HTTP cache headers), Output Caching is entirely server-controlled.
|
|
6
|
+
|
|
7
|
+
## Key Features
|
|
8
|
+
|
|
9
|
+
| Feature | Response Caching | Output Caching |
|
|
10
|
+
|---------|------------------|----------------|
|
|
11
|
+
| Cache Location | Client/Proxy (HTTP headers) | Server-side |
|
|
12
|
+
| Control | HTTP Cache-Control headers | Server policies |
|
|
13
|
+
| Invalidation | Limited (time-based) | ✅ Tag-based programmatic |
|
|
14
|
+
| Distributed Support | ❌ | ✅ Redis backend |
|
|
15
|
+
| Policy-based | ❌ | ✅ Named policies |
|
|
16
|
+
| Vary Support | Limited | ✅ Query, Header, Route |
|
|
17
|
+
|
|
18
|
+
## Getting Started
|
|
19
|
+
|
|
20
|
+
### Basic Setup (In-Memory)
|
|
21
|
+
|
|
22
|
+
```csharp
|
|
23
|
+
// Program.cs
|
|
24
|
+
builder.Services.AddMvp24HoursOutputCache();
|
|
25
|
+
|
|
26
|
+
var app = builder.Build();
|
|
27
|
+
|
|
28
|
+
app.UseRouting();
|
|
29
|
+
app.UseMvp24HoursOutputCache();
|
|
30
|
+
app.MapControllers();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### With Standard Policies
|
|
34
|
+
|
|
35
|
+
```csharp
|
|
36
|
+
builder.Services.AddMvp24HoursOutputCache(options =>
|
|
37
|
+
{
|
|
38
|
+
options.DefaultExpirationTimeSpan = TimeSpan.FromMinutes(5);
|
|
39
|
+
options.AddStandardPolicies(); // Adds: Default, Short, Medium, Long, NoCache
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### With Redis Backend (Distributed)
|
|
44
|
+
|
|
45
|
+
```csharp
|
|
46
|
+
// For multi-instance deployments
|
|
47
|
+
builder.Services.AddMvp24HoursOutputCacheWithRedis(
|
|
48
|
+
"localhost:6379",
|
|
49
|
+
options =>
|
|
50
|
+
{
|
|
51
|
+
options.AddStandardPolicies();
|
|
52
|
+
options.RedisInstanceName = "myapp:oc:";
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Named Policies
|
|
57
|
+
|
|
58
|
+
Mvp24Hours provides several preset policies:
|
|
59
|
+
|
|
60
|
+
| Policy | Duration | Use Case |
|
|
61
|
+
|--------|----------|----------|
|
|
62
|
+
| `NoCache` | None | Disable caching |
|
|
63
|
+
| `Short` | 1 minute | Frequently changing data |
|
|
64
|
+
| `Medium` | 10 minutes | Moderately changing data |
|
|
65
|
+
| `Long` | 1 hour | Rarely changing data |
|
|
66
|
+
| `VeryLong` | 24 hours | Static content |
|
|
67
|
+
| `Authenticated` | 5 minutes | User-specific data (varies by Authorization) |
|
|
68
|
+
| `Api` | 5 minutes | API responses (varies by Accept header) |
|
|
69
|
+
|
|
70
|
+
### Using Policies with Minimal APIs
|
|
71
|
+
|
|
72
|
+
```csharp
|
|
73
|
+
// Using named policy
|
|
74
|
+
app.MapGet("/products", GetProducts)
|
|
75
|
+
.CacheOutput("Medium");
|
|
76
|
+
|
|
77
|
+
// Using Mvp24Hours extension
|
|
78
|
+
app.MapGet("/products", GetProducts)
|
|
79
|
+
.CacheOutputWithPolicy("Medium");
|
|
80
|
+
|
|
81
|
+
// Inline configuration
|
|
82
|
+
app.MapGet("/products", GetProducts)
|
|
83
|
+
.CacheOutputFor(
|
|
84
|
+
TimeSpan.FromMinutes(5),
|
|
85
|
+
tags: new[] { "products" },
|
|
86
|
+
varyByQuery: new[] { "category", "page" });
|
|
87
|
+
|
|
88
|
+
// Disable caching
|
|
89
|
+
app.MapPost("/orders", CreateOrder)
|
|
90
|
+
.NoCacheOutput();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Using Policies with Controllers
|
|
94
|
+
|
|
95
|
+
```csharp
|
|
96
|
+
[ApiController]
|
|
97
|
+
[Route("api/[controller]")]
|
|
98
|
+
public class ProductsController : ControllerBase
|
|
99
|
+
{
|
|
100
|
+
// Use named policy
|
|
101
|
+
[HttpGet]
|
|
102
|
+
[OutputCache(PolicyName = "Medium")]
|
|
103
|
+
public async Task<IActionResult> GetAll()
|
|
104
|
+
{
|
|
105
|
+
// ...
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Custom configuration
|
|
109
|
+
[HttpGet("{id}")]
|
|
110
|
+
[OutputCache(Duration = 60, VaryByRouteValueNames = new[] { "id" })]
|
|
111
|
+
public async Task<IActionResult> GetById(int id)
|
|
112
|
+
{
|
|
113
|
+
// ...
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Disable caching
|
|
117
|
+
[HttpPost]
|
|
118
|
+
[OutputCache(NoStore = true)]
|
|
119
|
+
public async Task<IActionResult> Create([FromBody] ProductDto dto)
|
|
120
|
+
{
|
|
121
|
+
// ...
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Custom Policies
|
|
127
|
+
|
|
128
|
+
### Creating Named Policies
|
|
129
|
+
|
|
130
|
+
```csharp
|
|
131
|
+
builder.Services.AddMvp24HoursOutputCache(options =>
|
|
132
|
+
{
|
|
133
|
+
// Products policy with tags for selective invalidation
|
|
134
|
+
options.AddPolicy("Products", p => p
|
|
135
|
+
.Expire(TimeSpan.FromMinutes(10))
|
|
136
|
+
.SetTags("products", "catalog")
|
|
137
|
+
.SetVaryByQuery("category", "page", "sort"));
|
|
138
|
+
|
|
139
|
+
// User-specific content
|
|
140
|
+
options.AddPolicy("UserProfile", p => p
|
|
141
|
+
.Expire(TimeSpan.FromMinutes(5))
|
|
142
|
+
.SetVaryByHeader("Authorization")
|
|
143
|
+
.SetTags("users")
|
|
144
|
+
.AllowAuthenticatedRequests());
|
|
145
|
+
|
|
146
|
+
// Search results with all query parameters
|
|
147
|
+
options.AddPolicy("Search", p => p
|
|
148
|
+
{
|
|
149
|
+
p.ExpirationTimeSpan = TimeSpan.FromMinutes(2);
|
|
150
|
+
p.VaryByAllQueryKeys = true;
|
|
151
|
+
p.Tags.Add("search");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Localized content
|
|
155
|
+
options.AddPolicy("Localized", p => p
|
|
156
|
+
.Expire(TimeSpan.FromHours(1))
|
|
157
|
+
.SetVaryByHeader("Accept-Language")
|
|
158
|
+
.SetTags("content"));
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Cache Invalidation
|
|
163
|
+
|
|
164
|
+
### Tag-based Invalidation
|
|
165
|
+
|
|
166
|
+
Output Caching supports tag-based invalidation through `IOutputCacheInvalidator`:
|
|
167
|
+
|
|
168
|
+
```csharp
|
|
169
|
+
public class ProductService
|
|
170
|
+
{
|
|
171
|
+
private readonly IProductRepository _repository;
|
|
172
|
+
private readonly IOutputCacheInvalidator _cacheInvalidator;
|
|
173
|
+
|
|
174
|
+
public ProductService(
|
|
175
|
+
IProductRepository repository,
|
|
176
|
+
IOutputCacheInvalidator cacheInvalidator)
|
|
177
|
+
{
|
|
178
|
+
_repository = repository;
|
|
179
|
+
_cacheInvalidator = cacheInvalidator;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public async Task<Product> CreateProductAsync(ProductDto dto)
|
|
183
|
+
{
|
|
184
|
+
var product = await _repository.CreateAsync(dto);
|
|
185
|
+
|
|
186
|
+
// Invalidate all product-related cache entries
|
|
187
|
+
await _cacheInvalidator.EvictByTagAsync("products");
|
|
188
|
+
|
|
189
|
+
return product;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public async Task UpdateProductAsync(int id, ProductDto dto)
|
|
193
|
+
{
|
|
194
|
+
await _repository.UpdateAsync(id, dto);
|
|
195
|
+
|
|
196
|
+
// Invalidate specific product and general product list
|
|
197
|
+
await _cacheInvalidator.EvictByTagsAsync(new[]
|
|
198
|
+
{
|
|
199
|
+
"products",
|
|
200
|
+
$"product:{id}"
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Using with CQRS Commands
|
|
207
|
+
|
|
208
|
+
```csharp
|
|
209
|
+
public class CreateProductCommandHandler : ICommandHandler<CreateProductCommand, Product>
|
|
210
|
+
{
|
|
211
|
+
private readonly IProductRepository _repository;
|
|
212
|
+
private readonly IOutputCacheInvalidator _cacheInvalidator;
|
|
213
|
+
|
|
214
|
+
public async Task<Product> Handle(
|
|
215
|
+
CreateProductCommand command,
|
|
216
|
+
CancellationToken cancellationToken)
|
|
217
|
+
{
|
|
218
|
+
var product = await _repository.CreateAsync(command.Data);
|
|
219
|
+
|
|
220
|
+
// Invalidate cache after successful command
|
|
221
|
+
await _cacheInvalidator.EvictByTagAsync("products", cancellationToken);
|
|
222
|
+
|
|
223
|
+
return product;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Vary-By Strategies
|
|
229
|
+
|
|
230
|
+
### Vary By Query String
|
|
231
|
+
|
|
232
|
+
```csharp
|
|
233
|
+
// Vary by specific keys
|
|
234
|
+
options.AddPolicy("Search", p => p
|
|
235
|
+
.SetVaryByQuery("q", "page", "size")
|
|
236
|
+
.Expire(TimeSpan.FromMinutes(2)));
|
|
237
|
+
|
|
238
|
+
// Vary by all query keys
|
|
239
|
+
options.AddPolicy("DynamicSearch", p => p
|
|
240
|
+
{
|
|
241
|
+
p.VaryByAllQueryKeys = true;
|
|
242
|
+
p.ExpirationTimeSpan = TimeSpan.FromMinutes(2);
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Vary By Header
|
|
247
|
+
|
|
248
|
+
```csharp
|
|
249
|
+
// Vary by Accept-Language for localized content
|
|
250
|
+
options.AddPolicy("Localized", p => p
|
|
251
|
+
.SetVaryByHeader("Accept-Language")
|
|
252
|
+
.Expire(TimeSpan.FromHours(1)));
|
|
253
|
+
|
|
254
|
+
// Vary by multiple headers
|
|
255
|
+
options.AddPolicy("MultiHeader", p => p
|
|
256
|
+
.SetVaryByHeader("Accept", "Accept-Language", "Accept-Encoding")
|
|
257
|
+
.Expire(TimeSpan.FromMinutes(30)));
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Vary By Route Values
|
|
261
|
+
|
|
262
|
+
```csharp
|
|
263
|
+
// Vary by route parameters
|
|
264
|
+
options.AddPolicy("EntityDetails", p => p
|
|
265
|
+
.SetVaryByRouteValue("id")
|
|
266
|
+
.Expire(TimeSpan.FromMinutes(10)));
|
|
267
|
+
|
|
268
|
+
// Minimal API usage
|
|
269
|
+
app.MapGet("/products/{id}", GetProductById)
|
|
270
|
+
.CacheOutput(policy => policy
|
|
271
|
+
.Expire(TimeSpan.FromMinutes(10))
|
|
272
|
+
.SetVaryByRouteValue("id")
|
|
273
|
+
.Tag($"products"));
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Redis Integration
|
|
277
|
+
|
|
278
|
+
### Why Use Redis for Output Caching?
|
|
279
|
+
|
|
280
|
+
- **Multi-instance deployments:** Cache is shared across all instances
|
|
281
|
+
- **Persistence:** Cache survives application restarts
|
|
282
|
+
- **Scalability:** Offload memory usage to Redis
|
|
283
|
+
- **Centralized invalidation:** Invalidate across all instances
|
|
284
|
+
|
|
285
|
+
### Configuration
|
|
286
|
+
|
|
287
|
+
```csharp
|
|
288
|
+
builder.Services.AddMvp24HoursOutputCacheWithRedis(
|
|
289
|
+
"localhost:6379,abortConnect=false",
|
|
290
|
+
options =>
|
|
291
|
+
{
|
|
292
|
+
options.RedisInstanceName = "myapp:oc:";
|
|
293
|
+
options.DefaultExpirationTimeSpan = TimeSpan.FromMinutes(10);
|
|
294
|
+
options.AddStandardPolicies();
|
|
295
|
+
|
|
296
|
+
// Custom policies
|
|
297
|
+
options.AddPolicy("Products", p => p
|
|
298
|
+
.Expire(TimeSpan.FromMinutes(5))
|
|
299
|
+
.SetTags("products"));
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Redis Connection Options
|
|
304
|
+
|
|
305
|
+
```csharp
|
|
306
|
+
builder.Services.AddMvp24HoursOutputCache(options =>
|
|
307
|
+
{
|
|
308
|
+
options.UseDistributedCache = true;
|
|
309
|
+
options.RedisConnectionString =
|
|
310
|
+
"redis-server:6379,password=secret,ssl=True,abortConnect=false";
|
|
311
|
+
options.RedisInstanceName = "prod:oc:";
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Excluded Paths
|
|
316
|
+
|
|
317
|
+
```csharp
|
|
318
|
+
builder.Services.AddMvp24HoursOutputCache(options =>
|
|
319
|
+
{
|
|
320
|
+
// Exclude specific paths from caching
|
|
321
|
+
options.ExcludedPaths.Add("/api/health");
|
|
322
|
+
options.ExcludedPaths.Add("/api/admin/*");
|
|
323
|
+
options.ExcludedPaths.Add("/api/auth/*");
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Configuration Options
|
|
328
|
+
|
|
329
|
+
### OutputCachingOptions Properties
|
|
330
|
+
|
|
331
|
+
| Property | Type | Default | Description |
|
|
332
|
+
|----------|------|---------|-------------|
|
|
333
|
+
| `Enabled` | bool | `true` | Enable/disable output caching |
|
|
334
|
+
| `DefaultExpirationTimeSpan` | TimeSpan | 5 min | Default cache duration |
|
|
335
|
+
| `MaximumBodySize` | long | 100 MB | Maximum response size to cache |
|
|
336
|
+
| `SizeLimit` | long | 100 MB | Total cache size limit |
|
|
337
|
+
| `UseDistributedCache` | bool | `false` | Enable Redis backend |
|
|
338
|
+
| `RedisConnectionString` | string? | null | Redis connection string |
|
|
339
|
+
| `RedisInstanceName` | string | `"mvp24h-oc:"` | Redis key prefix |
|
|
340
|
+
| `UseCaseSensitivePaths` | bool | `false` | Case-sensitive cache keys |
|
|
341
|
+
| `VaryByQueryStringByDefault` | bool | `true` | Default vary by query |
|
|
342
|
+
| `CacheableMethods` | HashSet | GET, HEAD | HTTP methods to cache |
|
|
343
|
+
| `CacheableStatusCodes` | HashSet | 200 | Status codes to cache |
|
|
344
|
+
|
|
345
|
+
### OutputCachePolicyOptions Properties
|
|
346
|
+
|
|
347
|
+
| Property | Type | Description |
|
|
348
|
+
|----------|------|-------------|
|
|
349
|
+
| `ExpirationTimeSpan` | TimeSpan? | Cache duration |
|
|
350
|
+
| `NoCache` | bool | Disable caching |
|
|
351
|
+
| `Tags` | HashSet | Invalidation tags |
|
|
352
|
+
| `VaryByHeader` | HashSet | Headers to vary by |
|
|
353
|
+
| `VaryByQueryKeys` | HashSet | Query keys to vary by |
|
|
354
|
+
| `VaryByAllQueryKeys` | bool | Vary by all query keys |
|
|
355
|
+
| `VaryByRouteValue` | HashSet | Route values to vary by |
|
|
356
|
+
| `LockDuringPopulation` | bool | Prevent stampede |
|
|
357
|
+
| `CacheAuthenticatedRequests` | bool | Cache authenticated requests |
|
|
358
|
+
|
|
359
|
+
## Best Practices
|
|
360
|
+
|
|
361
|
+
### 1. Use Tags for Invalidation Groups
|
|
362
|
+
|
|
363
|
+
```csharp
|
|
364
|
+
options.AddPolicy("Products", p => p
|
|
365
|
+
.Expire(TimeSpan.FromMinutes(10))
|
|
366
|
+
.SetTags("products", "catalog"));
|
|
367
|
+
|
|
368
|
+
// Invalidate by tag when data changes
|
|
369
|
+
await _cacheInvalidator.EvictByTagAsync("products");
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 2. Appropriate Cache Durations
|
|
373
|
+
|
|
374
|
+
```csharp
|
|
375
|
+
// Frequently changing data - short cache
|
|
376
|
+
options.AddPolicy("RealTimeData", p => p.Expire(TimeSpan.FromSeconds(30)));
|
|
377
|
+
|
|
378
|
+
// Reference data - long cache
|
|
379
|
+
options.AddPolicy("ReferenceData", p => p.Expire(TimeSpan.FromHours(24)));
|
|
380
|
+
|
|
381
|
+
// User-specific data - medium cache with Authorization vary
|
|
382
|
+
options.AddPolicy("UserData", p => p
|
|
383
|
+
.Expire(TimeSpan.FromMinutes(5))
|
|
384
|
+
.SetVaryByHeader("Authorization"));
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### 3. Exclude Sensitive Endpoints
|
|
388
|
+
|
|
389
|
+
```csharp
|
|
390
|
+
options.ExcludedPaths.Add("/api/auth/*");
|
|
391
|
+
options.ExcludedPaths.Add("/api/payments/*");
|
|
392
|
+
options.ExcludedPaths.Add("/api/admin/*");
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 4. Use Redis for Production
|
|
396
|
+
|
|
397
|
+
```csharp
|
|
398
|
+
if (builder.Environment.IsProduction())
|
|
399
|
+
{
|
|
400
|
+
builder.Services.AddMvp24HoursOutputCacheWithRedis(
|
|
401
|
+
configuration["Redis:ConnectionString"]!);
|
|
402
|
+
}
|
|
403
|
+
else
|
|
404
|
+
{
|
|
405
|
+
builder.Services.AddMvp24HoursOutputCache();
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### 5. Combine with HybridCache
|
|
410
|
+
|
|
411
|
+
Output Caching and HybridCache serve different purposes:
|
|
412
|
+
|
|
413
|
+
- **Output Caching:** Cache complete HTTP responses
|
|
414
|
+
- **HybridCache:** Cache application-level data
|
|
415
|
+
|
|
416
|
+
```csharp
|
|
417
|
+
// Output caching for HTTP responses
|
|
418
|
+
builder.Services.AddMvp24HoursOutputCache(options =>
|
|
419
|
+
{
|
|
420
|
+
options.AddStandardPolicies();
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// HybridCache for application data
|
|
424
|
+
builder.Services.AddMvpHybridCache();
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Pipeline Position
|
|
428
|
+
|
|
429
|
+
```csharp
|
|
430
|
+
var app = builder.Build();
|
|
431
|
+
|
|
432
|
+
// Exception handling first
|
|
433
|
+
app.UseMvp24HoursProblemDetails();
|
|
434
|
+
|
|
435
|
+
// Then CORS
|
|
436
|
+
app.UseCors();
|
|
437
|
+
|
|
438
|
+
// Then authentication/authorization
|
|
439
|
+
app.UseAuthentication();
|
|
440
|
+
app.UseAuthorization();
|
|
441
|
+
|
|
442
|
+
// Output caching after auth (to respect Authorization vary)
|
|
443
|
+
app.UseMvp24HoursOutputCache();
|
|
444
|
+
|
|
445
|
+
// Then routing
|
|
446
|
+
app.MapControllers();
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## See Also
|
|
450
|
+
|
|
451
|
+
- [HybridCache](hybrid-cache.md) - Application-level caching
|
|
452
|
+
- [Rate Limiting](rate-limiting.md) - Request throttling
|
|
453
|
+
- [HTTP Resilience](http-resilience.md) - HTTP client resilience
|
|
454
|
+
|