ASP.NET Core'da çıkış önbelleğe alma ara yazılımı
Tarafından Tom Dykstra
Uyarı
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.
Bu makalede, ASP.NET Core uygulamasında çıkış önbelleğe alma ara yazılımının nasıl yapılandırılması açıklanır. Çıkış önbelleğine giriş için bkz . Çıkış önbelleğe alma.
Çıktı önbelleğe alma ara yazılımı her tür ASP.NET Core uygulamasında kullanılabilir: Minimal API, Denetleyiciler, MVC ve Razor Sayfalar içeren Web API'leri. En düşük API'ler ve denetleyici tabanlı API'ler için kod örnekleri sağlanır. Denetleyici tabanlı API örnekleri, önbelleğe almayı yapılandırmak için özniteliklerin nasıl kullanılacağını gösterir. Bu öznitelikler MVC ve Razor Pages uygulamalarında da kullanılabilir.
Kod örnekleri, görüntü oluşturan ve tarih ve saatte "oluşturulan" bir gravatar sınıfına başvurur. sınıfı tanımlanır ve yalnızca örnek uygulamada kullanılır. Amacı, önbelleğe alınan çıkışın ne zaman kullanıldığını görmeyi kolaylaştırmaktır. Daha fazla bilgi için bkz. Örnek kodda örnek ve Önişlemci yönergelerini indirme.
Ara yazılımı uygulamaya ekleme
çağrısı AddOutputCacheyaparak çıkış önbelleğe alma ara yazılımını hizmet koleksiyonuna ekleyin.
ara yazılımı çağrısı UseOutputCacheyaparak istek işleme işlem hattına ekleyin.
Örneğin:
builder.Services.AddOutputCache();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseOutputCache();
app.UseAuthorization();
Çağrısı AddOutputCache
yapar ve UseOutputCache
önbelleğe alma davranışını başlatmaz, önbelleğe alma özelliğini kullanılabilir hale getirir. Uygulama önbelleği yanıtlarını oluşturmak için önbelleğe alma, aşağıdaki bölümlerde gösterildiği gibi yapılandırılmalıdır.
Not
Bir uç nokta veya sayfa yapılandırma
En düşük API uygulamaları için, aşağıdaki örneklerde gösterildiği gibi öğesini çağırarak CacheOutput
veya özniteliğini uygulayarak [OutputCache]
önbelleğe alma yapacak bir uç nokta yapılandırın:
app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput();
app.MapGet("/attribute", [OutputCache] (context) =>
Gravatar.WriteGravatar(context));
Denetleyicili uygulamalar için özniteliğini [OutputCache]
burada gösterildiği gibi eylem yöntemine uygulayın:
[ApiController]
[Route("/[controller]")]
[OutputCache]
public class CachedController : ControllerBase
{
public async Task GetAsync()
{
await Gravatar.WriteGravatar(HttpContext);
}
}
Pages uygulamaları için Razor özniteliğini sayfa sınıfına Razor uygulayın.
Birden çok uç nokta veya sayfa yapılandırma
Birden çok uç noktaya uygulanan önbelleğe alma yapılandırmasını belirtmek için ararken AddOutputCache
ilkeler oluşturun. Belirli uç noktalar için bir ilke seçilebilirken, temel ilke bir uç nokta koleksiyonu için varsayılan önbelleğe alma yapılandırması sağlar.
Aşağıdaki vurgulanmış kod, uygulamanın tüm uç noktaları için önbelleğe alma işlemini 10 saniyelik süreyle yapılandırıyor. Süre sonu belirtilmezse, varsayılan olarak bir dakika olur.
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder =>
builder.Expire(TimeSpan.FromSeconds(10)));
options.AddPolicy("Expire20", builder =>
builder.Expire(TimeSpan.FromSeconds(20)));
options.AddPolicy("Expire30", builder =>
builder.Expire(TimeSpan.FromSeconds(30)));
});
Aşağıdaki vurgulanmış kod, her birinde farklı bir süre sonu belirten iki ilke oluşturur. Seçilen uç noktalar 20 saniyelik süre sonunu, diğerleri ise 30 saniyelik süre sonunu kullanabilir.
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder =>
builder.Expire(TimeSpan.FromSeconds(10)));
options.AddPolicy("Expire20", builder =>
builder.Expire(TimeSpan.FromSeconds(20)));
options.AddPolicy("Expire30", builder =>
builder.Expire(TimeSpan.FromSeconds(30)));
});
Yöntemini çağırırken CacheOutput
veya özniteliğini kullanarak [OutputCache]
uç nokta için bir ilke seçebilirsiniz.
En düşük API uygulamasında aşağıdaki kod, 20 saniyelik süre sonu ve 30 saniyelik süre sonu olan bir uç nokta yapılandırmaktadır:
app.MapGet("/20", Gravatar.WriteGravatar).CacheOutput("Expire20");
app.MapGet("/30", [OutputCache(PolicyName = "Expire30")] (context) =>
Gravatar.WriteGravatar(context));
Denetleyicili uygulamalar için, bir ilke seçmek için eylem yöntemine özniteliğini uygulayın [OutputCache]
:
[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "Expire20")]
public class Expire20Controller : ControllerBase
{
public async Task GetAsync()
{
await Gravatar.WriteGravatar(HttpContext);
}
}
Pages uygulamaları için Razor özniteliğini sayfa sınıfına Razor uygulayın.
Varsayılan çıkış önbelleğe alma ilkesi
Varsayılan olarak, çıktı önbelleğe alma şu kuralları izler:
- Yalnızca HTTP 200 yanıtları önbelleğe alınır.
- Yalnızca HTTP GET veya HEAD istekleri önbelleğe alınır.
- Tanımlama bilgilerini ayarlayan yanıtlar önbelleğe alınmaz.
- Kimliği doğrulanmış isteklere verilen yanıtlar önbelleğe alınmaz.
Aşağıdaki kod, varsayılan önbelleğe alma kurallarının tümünü uygulamanın tüm uç noktalarına uygular:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder.Cache());
});
Varsayılan ilkeyi geçersiz kılma
Aşağıdaki kod, varsayılan kuralların nasıl geçersiz kılınacaklarını gösterir. Aşağıdaki özel ilke kodunda vurgulanan satırlar, HTTP POST yöntemleri ve HTTP 301 yanıtları için önbelleğe almayı etkinleştirir:
using Microsoft.AspNetCore.OutputCaching;
using Microsoft.Extensions.Primitives;
namespace OCMinimal;
public sealed class MyCustomPolicy : IOutputCachePolicy
{
public static readonly MyCustomPolicy Instance = new();
private MyCustomPolicy()
{
}
ValueTask IOutputCachePolicy.CacheRequestAsync(
OutputCacheContext context,
CancellationToken cancellationToken)
{
var attemptOutputCaching = AttemptOutputCaching(context);
context.EnableOutputCaching = true;
context.AllowCacheLookup = attemptOutputCaching;
context.AllowCacheStorage = attemptOutputCaching;
context.AllowLocking = true;
// Vary by any query by default
context.CacheVaryByRules.QueryKeys = "*";
return ValueTask.CompletedTask;
}
ValueTask IOutputCachePolicy.ServeFromCacheAsync
(OutputCacheContext context, CancellationToken cancellationToken)
{
return ValueTask.CompletedTask;
}
ValueTask IOutputCachePolicy.ServeResponseAsync
(OutputCacheContext context, CancellationToken cancellationToken)
{
var response = context.HttpContext.Response;
// Verify existence of cookie headers
if (!StringValues.IsNullOrEmpty(response.Headers.SetCookie))
{
context.AllowCacheStorage = false;
return ValueTask.CompletedTask;
}
// Check response code
if (response.StatusCode != StatusCodes.Status200OK &&
response.StatusCode != StatusCodes.Status301MovedPermanently)
{
context.AllowCacheStorage = false;
return ValueTask.CompletedTask;
}
return ValueTask.CompletedTask;
}
private static bool AttemptOutputCaching(OutputCacheContext context)
{
// Check if the current request fulfills the requirements
// to be cached
var request = context.HttpContext.Request;
// Verify the method
if (!HttpMethods.IsGet(request.Method) &&
!HttpMethods.IsHead(request.Method) &&
!HttpMethods.IsPost(request.Method))
{
return false;
}
// Verify existence of authorization headers
if (!StringValues.IsNullOrEmpty(request.Headers.Authorization) ||
request.HttpContext.User?.Identity?.IsAuthenticated == true)
{
return false;
}
return true;
}
}
Bu özel ilkeyi kullanmak için adlandırılmış bir ilke oluşturun:
builder.Services.AddOutputCache(options =>
{
options.AddPolicy("CachePost", MyCustomPolicy.Instance);
});
Bir uç nokta için adlandırılmış ilkeyi seçin. Aşağıdaki kod, en düşük API uygulamasındaki bir uç nokta için özel ilkeyi seçer:
app.MapPost("/cachedpost", Gravatar.WriteGravatar)
.CacheOutput("CachePost");
Aşağıdaki kod bir denetleyici eylemi için aynı işlemi yapar:
[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "CachePost")]
public class PostController : ControllerBase
{
public async Task GetAsync()
{
await Gravatar.WriteGravatar(HttpContext);
}
}
Alternatif varsayılan ilke geçersiz kılma
Alternatif olarak, özel ilke sınıfında aşağıdaki değişikliklerle bir örneği başlatmak için Bağımlılık Ekleme (DI) kullanın:
- Özel oluşturucu yerine ortak oluşturucu.
Instance
Özel ilke sınıfında özelliğini ortadan kaldırın.
Örneğin:
public sealed class MyCustomPolicy2 : IOutputCachePolicy
{
public MyCustomPolicy2()
{
}
Sınıfın geri kalanı daha önce gösterildiği gibi aynıdır. Aşağıdaki örnekte gösterildiği gibi özel ilkeyi ekleyin:
builder.Services.AddOutputCache(options =>
{
options.AddPolicy("CachePost", builder =>
builder.AddPolicy<MyCustomPolicy2>(), true);
});
Yukarıdaki kod, özel ilke sınıfının örneğini oluşturmak için DI kullanır. Oluşturucudaki tüm genel bağımsız değişkenler çözümlenir.
Özel bir ilkeyi temel ilke olarak kullanırken, çağırmayın OutputCache()
(bağımsız değişken olmadan) veya temel ilkenin [OutputCache]
geçerli olması gereken herhangi bir uç noktada özniteliğini kullanmayın. özniteliğini çağırmak OutputCache()
veya kullanmak, varsayılan ilkeyi uç noktaya ekler.
Önbellek anahtarını belirtme
Varsayılan olarak, URL'nin her bölümü bir önbellek girdisinin anahtarı olarak (şema, konak, bağlantı noktası, yol ve sorgu dizesi) eklenir. Ancak, önbellek anahtarını açıkça denetlemek isteyebilirsiniz. Örneğin, yalnızca sorgu dizesinin her benzersiz değeri culture
için benzersiz bir yanıt döndüren bir uç noktanız olduğunu varsayalım. URL'nin diğer bölümlerindeki varyasyon (diğer sorgu dizeleri gibi) farklı önbellek girdilerine neden olmamalıdır. Aşağıdaki vurgulanmış kodda gösterildiği gibi bir ilkede bu tür kuralları belirtebilirsiniz:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Ardından bir uç nokta için ilkeyi VaryByQuery
seçebilirsiniz. En düşük API uygulamasında aşağıdaki kod, yalnızca sorgu dizesinin VaryByQuery
her benzersiz değeri için benzersiz yanıt döndüren bir uç nokta için ilkeyi culture
seçer:
app.MapGet("/query", Gravatar.WriteGravatar).CacheOutput("Query");
Aşağıdaki kod bir denetleyici eylemi için aynı işlemi yapar:
[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "Query")]
public class QueryController : ControllerBase
{
public async Task GetAsync()
{
await Gravatar.WriteGravatar(HttpContext);
}
}
Önbellek anahtarını denetleme seçeneklerinden bazıları şunlardır:
SetVaryByQuery - Önbellek anahtarına eklenecek bir veya daha fazla sorgu dizesi adı belirtin.
SetVaryByHeader - Önbellek anahtarına eklenecek bir veya daha fazla HTTP üst bilgisi belirtin.
VaryByValue- Önbellek anahtarına eklenecek değeri belirtin. Aşağıdaki örnek, geçerli sunucu saatinin saniye olarak tek mi yoksa çift mi olduğunu gösteren bir değer kullanır. Yeni yanıt yalnızca saniye sayısı tekten çifte, hatta teke geçtiğinde oluşturulur.
builder.Services.AddOutputCache(options => { options.AddBasePolicy(builder => builder .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog")) .Tag("tag-blog")); options.AddBasePolicy(builder => builder.Tag("tag-all")); options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture")); options.AddPolicy("NoCache", builder => builder.NoCache()); options.AddPolicy("NoLock", builder => builder.SetLocking(false)); options.AddPolicy("VaryByValue", builder => builder.VaryByValue((context) => new KeyValuePair<string, string>( "time", (DateTime.Now.Second % 2) .ToString(CultureInfo.InvariantCulture)))); });
Anahtarın yol bölümünün büyük/küçük harfe duyarlı olduğunu belirtmek için kullanın OutputCacheOptions.UseCaseSensitivePaths . Varsayılan, büyük/küçük harfe duyarsızdır.
Diğer seçenekler için sınıfına OutputCachePolicyBuilder bakın.
Önbellek yeniden doğrulama
Önbellek yeniden doğrulama, sunucunun tam yanıt gövdesi yerine bir 304 Not Modified
HTTP durum kodu döndürebileceği anlamına gelir. Bu durum kodu, istemciye istek yanıtının istemcinin daha önce aldığı yanıttan değişmediğini bildirir.
Aşağıdaki kod, önbellek yeniden doğrulamasını etkinleştirmek için üst Etag
bilgi kullanımını gösterir. İstemci önceki bir yanıtın etag değeriyle bir If-None-Match
üst bilgi gönderirse ve önbellek girdisi yeniyse, sunucu tam yanıt yerine 304 Değiştirilmedi değerini döndürür. Minimal API uygulamasında bir ilkede etag değerini şu şekilde ayarlayabilirsiniz:
app.MapGet("/etag", async (context) =>
{
var etag = $"\"{Guid.NewGuid():n}\"";
context.Response.Headers.ETag = etag;
await Gravatar.WriteGravatar(context);
}).CacheOutput();
Denetleyici tabanlı API'de etag değerini şu şekilde ayarlayabilirsiniz:
[ApiController]
[Route("/[controller]")]
[OutputCache]
public class EtagController : ControllerBase
{
public async Task GetAsync()
{
var etag = $"\"{Guid.NewGuid():n}\"";
HttpContext.Response.Headers.ETag = etag;
await Gravatar.WriteGravatar(HttpContext);
}
}
Önbellek yeniden doğrulamasını gerçekleştirmenin bir diğer yolu da, istemci tarafından istenen tarihle karşılaştırıldığında önbellek girdisi oluşturma tarihini denetlemektir. İstek üst bilgisi If-Modified-Since
sağlandığında, önbelleğe alınan girdi daha eskiyse ve süresi dolmadıysa çıkış önbelleğe alma 304 döndürür.
önbellek yeniden doğrulama, istemciden gönderilen bu üst bilgiler yanıt olarak otomatiktir. Çıktı önbelleğini etkinleştirmenin yanı sıra bu davranışı etkinleştirmek için sunucuda özel bir yapılandırma gerekmez.
Önbellek girdilerini çıkarmak için etiketleri kullanma
Bir grup uç noktayı tanımlamak ve grubun tüm önbellek girdilerini çıkarmak için etiketleri kullanabilirsiniz. Örneğin, aşağıdaki minimum API kodu URL'leri "blog" ile başlayan ve bunları "tag-blog" olarak etiketleyen bir çift uç nokta oluşturur:
app.MapGet("/blog", Gravatar.WriteGravatar)
.CacheOutput(builder => builder.Tag("tag-blog"));
app.MapGet("/blog/post/{id}", Gravatar.WriteGravatar)
.CacheOutput(builder => builder.Tag("tag-blog"));
Aşağıdaki kodda, denetleyici tabanlı API'de bir uç noktaya etiketlerin nasıl atandığı gösterilmektedir:
[ApiController]
[Route("/[controller]")]
[OutputCache(Tags = new[] { "tag-blog", "tag-all" })]
public class TagEndpointController : ControllerBase
{
public async Task GetAsync()
{
await Gravatar.WriteGravatar(HttpContext);
}
}
Ile başlayan blog
yolları olan uç noktalara etiket atamanın alternatif bir yolu, bu yola sahip tüm uç noktalara uygulanan bir temel ilke tanımlamaktır. Aşağıdaki kod bunun nasıl yapılacağını gösterir:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
En düşük API uygulamalarının bir diğer alternatifi de çağrısı MapGroup
yapmaktır:
var blog = app.MapGroup("blog")
.CacheOutput(builder => builder.Tag("tag-blog"));
blog.MapGet("/", Gravatar.WriteGravatar);
blog.MapGet("/post/{id}", Gravatar.WriteGravatar);
Yukarıdaki etiket atama örneklerinde her iki uç nokta da etiket tarafından tag-blog
tanımlanır. Ardından bu uç noktaların önbellek girdilerini şu etikete başvuran tek bir deyimle çıkarabilirsiniz:
app.MapPost("/purge/{tag}", async (IOutputCacheStore cache, string tag) =>
{
await cache.EvictByTagAsync(tag, default);
});
Bu kodla, öğesine https://localhost:<port>/purge/tag-blog
gönderilen bir HTTP POST isteği bu uç noktalar için önbellek girdilerini kaldırır.
Tüm uç noktalar için tüm önbellek girdilerini çıkarmanın bir yolunu isteyebilirsiniz. Bunu yapmak için, aşağıdaki kodda olduğu gibi tüm uç noktalar için bir temel ilke oluşturun:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Bu temel ilke, önbellekteki her şeyi çıkarmak için "tag-all" etiketini kullanmanıza olanak tanır.
Kaynak kilitlemeyi devre dışı bırakma
Varsayılan olarak, önbellek damgalı ve gürleyen sürü riskini azaltmak için kaynak kilitleme etkinleştirilir. Daha fazla bilgi için bkz . Çıktı Önbelleğe Alma.
Kaynak kilitlemeyi devre dışı bırakmak için, aşağıdaki örnekte gösterildiği gibi bir ilke oluştururken SetLocking(false) öğesini çağırın:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Aşağıdaki örnek, en düşük API uygulamasındaki bir uç nokta için kilitlememe ilkesini seçer:
app.MapGet("/nolock", Gravatar.WriteGravatar)
.CacheOutput("NoLock");
Denetleyici tabanlı API'de, ilkeyi seçmek için özniteliğini kullanın:
[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "NoLock")]
public class NoLockController : ControllerBase
{
public async Task GetAsync()
{
await Gravatar.WriteGravatar(HttpContext);
}
}
Sınırlar
aşağıdaki özellikleri OutputCacheOptions , tüm uç noktalara uygulanan sınırları yapılandırmanıza olanak sağlar:
- SizeLimit - En büyük önbellek depolama alanı boyutu. Bu sınıra ulaşıldığında, eski girdiler çıkarılana kadar yeni yanıtlar önbelleğe alınmaz. Varsayılan değer 100 MB'tır.
- MaximumBodySize - Yanıt gövdesi bu sınırı aşarsa önbelleğe alınmaz. Varsayılan değer 64 MB'tır.
- DefaultExpirationTimeSpan - İlke tarafından belirtilmediğinde geçerli olan süre sonu süresi. Varsayılan değer 60 saniyedir.
Önbellek depolama
IOutputCacheStore depolama için kullanılır. Varsayılan olarak ile MemoryCachekullanılır. Önbelleğe alınan yanıtlar işlem içinde depolanır, bu nedenle sunucu işlemi her yeniden başlatıldığında her sunucunun kaybedilen ayrı bir önbelleği vardır.
Redis Cache
Alternatif olarak Redis önbelleğini kullanabilirsiniz. Redis cache, tek tek sunucu işlemlerinden daha uzun süre çalışan paylaşılan bir önbellek aracılığıyla sunucu düğümleri arasında tutarlılık sağlar. Çıkış önbelleği için Redis'i kullanmak için:
Microsoft.AspNetCore.OutputCaching.StackExchangeRedis NuGet paketini yükleyin.
Çağrısı
builder.Services.AddStackExchangeRedisOutputCache
(değilAddStackExchangeRedisCache
) ve Redis sunucusuna işaret eden bir bağlantı dizesi sağlayın.Örneğin:
builder.Services.AddStackExchangeRedisOutputCache(options => { options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr"); options.InstanceName = "SampleInstance"; }); builder.Services.AddOutputCache(options => { options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromSeconds(10))); });
options.Configuration
- Şirket içi Redis sunucusuna veya Redis için Azure Cache gibi barındırılan bir teklife bağlantı dizesi. Örneğin,<instance_name>.redis.cache.windows.net:6380,password=<password>,ssl=True,abortConnect=False
Redis için Azure önbelleği için.options.InstanceName
- İsteğe bağlı olarak, önbellek için bir mantıksal bölüm belirtir.
Yapılandırma seçenekleri Redis tabanlı dağıtılmış önbelleğe alma seçenekleriyle aynıdır.
IDistributedCache
önerilmez
Çıktı önbelleğe alma ile kullanılması önerilmez IDistributedCache . IDistributedCache
etiketleme için gereken atomik özelliklere sahip değildir. Redis için yerleşik desteği kullanmanızı veya temel depolama mekanizmasında doğrudan bağımlılıkları kullanarak özel IOutputCacheStore uygulamalar oluşturmanızı öneririz.
Ayrıca bkz.
Bu makalede, ASP.NET Core uygulamasında çıkış önbelleğe alma ara yazılımının nasıl yapılandırılması açıklanır. Çıkış önbelleğine giriş için bkz . Çıkış önbelleğe alma.
Çıktı önbelleğe alma ara yazılımı her tür ASP.NET Core uygulamasında kullanılabilir: Minimal API, Denetleyiciler, MVC ve Razor Sayfalar içeren Web API'leri. Örnek uygulama minimal bir API'dir, ancak göstermiş olduğu her önbelleğe alma özelliği diğer uygulama türlerinde de desteklenir.
Ara yazılımı uygulamaya ekleme
çağrısı AddOutputCacheyaparak çıkış önbelleğe alma ara yazılımını hizmet koleksiyonuna ekleyin.
ara yazılımı çağrısı UseOutputCacheyaparak istek işleme işlem hattına ekleyin.
Not
- CORS ara yazılımı kullanan uygulamalarda,
UseOutputCache
sonrasında UseCorsçağrılmalıdır. - Razor Pages uygulamaları ve denetleyicili uygulamalar bölümünden
UseOutputCache
sonraUseRouting
çağrılmalıdır. - Çağrısı
AddOutputCache
yapar veUseOutputCache
önbelleğe alma davranışını başlatmaz, önbelleğe alma özelliğini kullanılabilir hale getirir. Yanıt verilerini önbelleğe alma, aşağıdaki bölümlerde gösterildiği gibi yapılandırılmalıdır.
Bir uç nokta veya sayfa yapılandırma
En düşük API uygulamaları için, aşağıdaki örneklerde gösterildiği gibi öğesini çağırarak CacheOutput
veya özniteliğini uygulayarak [OutputCache]
önbelleğe alma yapacak bir uç nokta yapılandırın:
app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput();
app.MapGet("/attribute", [OutputCache] (context) =>
Gravatar.WriteGravatar(context));
Denetleyicili uygulamalar için özniteliğini [OutputCache]
eylem yöntemine uygulayın. Pages uygulamaları için Razor özniteliğini sayfa sınıfına Razor uygulayın.
Birden çok uç nokta veya sayfa yapılandırma
Birden çok uç noktaya uygulanan önbelleğe alma yapılandırmasını belirtmek için ararken AddOutputCache
ilkeler oluşturun. Belirli uç noktalar için bir ilke seçilebilirken, temel ilke bir uç nokta koleksiyonu için varsayılan önbelleğe alma yapılandırması sağlar.
Aşağıdaki vurgulanmış kod, uygulamanın tüm uç noktaları için önbelleğe alma işlemini 10 saniyelik süreyle yapılandırıyor. Süre sonu belirtilmezse, varsayılan olarak bir dakika olur.
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder =>
builder.Expire(TimeSpan.FromSeconds(10)));
options.AddPolicy("Expire20", builder =>
builder.Expire(TimeSpan.FromSeconds(20)));
options.AddPolicy("Expire30", builder =>
builder.Expire(TimeSpan.FromSeconds(30)));
});
Aşağıdaki vurgulanmış kod, her birinde farklı bir süre sonu belirten iki ilke oluşturur. Seçilen uç noktalar 20 saniyelik süre sonunu, diğerleri ise 30 saniyelik süre sonunu kullanabilir.
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder =>
builder.Expire(TimeSpan.FromSeconds(10)));
options.AddPolicy("Expire20", builder =>
builder.Expire(TimeSpan.FromSeconds(20)));
options.AddPolicy("Expire30", builder =>
builder.Expire(TimeSpan.FromSeconds(30)));
});
Yöntemini çağırırken CacheOutput
veya özniteliğini kullanarak [OutputCache]
uç nokta için bir ilke seçebilirsiniz:
app.MapGet("/20", Gravatar.WriteGravatar).CacheOutput("Expire20");
app.MapGet("/30", [OutputCache(PolicyName = "Expire30")] (context) =>
Gravatar.WriteGravatar(context));
Denetleyicili uygulamalar için özniteliğini [OutputCache]
eylem yöntemine uygulayın. Pages uygulamaları için Razor özniteliğini sayfa sınıfına Razor uygulayın.
Varsayılan çıkış önbelleğe alma ilkesi
Varsayılan olarak, çıktı önbelleğe alma şu kuralları izler:
- Yalnızca HTTP 200 yanıtları önbelleğe alınır.
- Yalnızca HTTP GET veya HEAD istekleri önbelleğe alınır.
- Tanımlama bilgilerini ayarlayan yanıtlar önbelleğe alınmaz.
- Kimliği doğrulanmış isteklere verilen yanıtlar önbelleğe alınmaz.
Aşağıdaki kod, varsayılan önbelleğe alma kurallarının tümünü uygulamanın tüm uç noktalarına uygular:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder.Cache());
});
Varsayılan ilkeyi geçersiz kılma
Aşağıdaki kod, varsayılan kuralların nasıl geçersiz kılınacaklarını gösterir. Aşağıdaki özel ilke kodunda vurgulanan satırlar, HTTP POST yöntemleri ve HTTP 301 yanıtları için önbelleğe almayı etkinleştirir:
using Microsoft.AspNetCore.OutputCaching;
using Microsoft.Extensions.Primitives;
namespace OCMinimal;
public sealed class MyCustomPolicy : IOutputCachePolicy
{
public static readonly MyCustomPolicy Instance = new();
private MyCustomPolicy()
{
}
ValueTask IOutputCachePolicy.CacheRequestAsync(
OutputCacheContext context,
CancellationToken cancellationToken)
{
var attemptOutputCaching = AttemptOutputCaching(context);
context.EnableOutputCaching = true;
context.AllowCacheLookup = attemptOutputCaching;
context.AllowCacheStorage = attemptOutputCaching;
context.AllowLocking = true;
// Vary by any query by default
context.CacheVaryByRules.QueryKeys = "*";
return ValueTask.CompletedTask;
}
ValueTask IOutputCachePolicy.ServeFromCacheAsync
(OutputCacheContext context, CancellationToken cancellationToken)
{
return ValueTask.CompletedTask;
}
ValueTask IOutputCachePolicy.ServeResponseAsync
(OutputCacheContext context, CancellationToken cancellationToken)
{
var response = context.HttpContext.Response;
// Verify existence of cookie headers
if (!StringValues.IsNullOrEmpty(response.Headers.SetCookie))
{
context.AllowCacheStorage = false;
return ValueTask.CompletedTask;
}
// Check response code
if (response.StatusCode != StatusCodes.Status200OK &&
response.StatusCode != StatusCodes.Status301MovedPermanently)
{
context.AllowCacheStorage = false;
return ValueTask.CompletedTask;
}
return ValueTask.CompletedTask;
}
private static bool AttemptOutputCaching(OutputCacheContext context)
{
// Check if the current request fulfills the requirements
// to be cached
var request = context.HttpContext.Request;
// Verify the method
if (!HttpMethods.IsGet(request.Method) &&
!HttpMethods.IsHead(request.Method) &&
!HttpMethods.IsPost(request.Method))
{
return false;
}
// Verify existence of authorization headers
if (!StringValues.IsNullOrEmpty(request.Headers.Authorization) ||
request.HttpContext.User?.Identity?.IsAuthenticated == true)
{
return false;
}
return true;
}
}
Bu özel ilkeyi kullanmak için adlandırılmış bir ilke oluşturun:
builder.Services.AddOutputCache(options =>
{
options.AddPolicy("CachePost", MyCustomPolicy.Instance);
});
Bir uç nokta için adlandırılmış ilkeyi seçin:
app.MapPost("/cachedpost", Gravatar.WriteGravatar)
.CacheOutput("CachePost");
Alternatif varsayılan ilke geçersiz kılma
Alternatif olarak, özel ilke sınıfında aşağıdaki değişikliklerle bir örneği başlatmak için Bağımlılık Ekleme (DI) kullanın:
- Özel oluşturucu yerine ortak oluşturucu.
Instance
Özel ilke sınıfında özelliğini ortadan kaldırın.
Örneğin:
public sealed class MyCustomPolicy2 : IOutputCachePolicy
{
public MyCustomPolicy2()
{
}
Sınıfın geri kalanı daha önce gösterildiği gibi aynıdır. Aşağıdaki örnekte gösterildiği gibi özel ilkeyi ekleyin:
builder.Services.AddOutputCache(options =>
{
options.AddPolicy("CachePost", builder =>
builder.AddPolicy<MyCustomPolicy2>(), true);
});
Yukarıdaki kod, özel ilke sınıfının örneğini oluşturmak için DI kullanır. Oluşturucudaki tüm genel bağımsız değişkenler çözümlenir.
Özel ilkeyi temel ilke olarak kullanırken, temel ilkenin geçerli olması gereken uç noktalarda (bağımsız değişken olmadan) çağırmayın OutputCache()
. Çağırma OutputCache()
, varsayılan ilkeyi uç noktaya ekler.
Önbellek anahtarını belirtme
Varsayılan olarak, URL'nin her bölümü bir önbellek girdisinin anahtarı olarak (şema, konak, bağlantı noktası, yol ve sorgu dizesi) eklenir. Ancak, önbellek anahtarını açıkça denetlemek isteyebilirsiniz. Örneğin, yalnızca sorgu dizesinin her benzersiz değeri culture
için benzersiz bir yanıt döndüren bir uç noktanız olduğunu varsayalım. URL'nin diğer bölümlerindeki varyasyon (diğer sorgu dizeleri gibi) farklı önbellek girdilerine neden olmamalıdır. Aşağıdaki vurgulanmış kodda gösterildiği gibi bir ilkede bu tür kuralları belirtebilirsiniz:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Ardından bir uç nokta için ilkeyi VaryByQuery
seçebilirsiniz:
app.MapGet("/query", Gravatar.WriteGravatar).CacheOutput("Query");
Önbellek anahtarını denetleme seçeneklerinden bazıları şunlardır:
SetVaryByQuery - Önbellek anahtarına eklenecek bir veya daha fazla sorgu dizesi adı belirtin.
SetVaryByHeader - Önbellek anahtarına eklenecek bir veya daha fazla HTTP üst bilgisi belirtin.
VaryByValue- Önbellek anahtarına eklenecek değeri belirtin. Aşağıdaki örnek, geçerli sunucu saatinin saniye olarak tek mi yoksa çift mi olduğunu gösteren bir değer kullanır. Yeni yanıt yalnızca saniye sayısı tekten çifte, hatta teke geçtiğinde oluşturulur.
app.MapGet("/varybyvalue", Gravatar.WriteGravatar) .CacheOutput(c => c.VaryByValue((context) => new KeyValuePair<string, string>( "time", (DateTime.Now.Second % 2) .ToString(CultureInfo.InvariantCulture))));
Anahtarın yol bölümünün büyük/küçük harfe duyarlı olduğunu belirtmek için kullanın OutputCacheOptions.UseCaseSensitivePaths . Varsayılan, büyük/küçük harfe duyarsızdır.
Diğer seçenekler için sınıfına OutputCachePolicyBuilder bakın.
Önbellek yeniden doğrulama
Önbellek yeniden doğrulama, sunucunun tam yanıt gövdesi yerine bir 304 Not Modified
HTTP durum kodu döndürebileceği anlamına gelir. Bu durum kodu, istemciye istek yanıtının istemcinin daha önce aldığı yanıttan değişmediğini bildirir.
Aşağıdaki kod, önbellek yeniden doğrulamasını etkinleştirmek için üst Etag
bilgi kullanımını gösterir. İstemci önceki bir yanıtın etag değerini içeren bir If-None-Match
üst bilgi gönderirse ve önbellek girdisi yeniyse, sunucu tam yanıt yerine 304 Değiştirilmedi değerini döndürür:
app.MapGet("/etag", async (context) =>
{
var etag = $"\"{Guid.NewGuid():n}\"";
context.Response.Headers.ETag = etag;
await Gravatar.WriteGravatar(context);
}).CacheOutput();
Önbellek yeniden doğrulamasını gerçekleştirmenin bir diğer yolu da, istemci tarafından istenen tarihle karşılaştırıldığında önbellek girdisi oluşturma tarihini denetlemektir. İstek üst bilgisi If-Modified-Since
sağlandığında, önbelleğe alınan girdi daha eskiyse ve süresi dolmadıysa çıkış önbelleğe alma 304 döndürür.
önbellek yeniden doğrulama, istemciden gönderilen bu üst bilgiler yanıt olarak otomatiktir. Çıktı önbelleğini etkinleştirmenin yanı sıra bu davranışı etkinleştirmek için sunucuda özel bir yapılandırma gerekmez.
Önbellek girdilerini çıkarmak için etiketleri kullanma
Bir grup uç noktayı tanımlamak ve grubun tüm önbellek girdilerini çıkarmak için etiketleri kullanabilirsiniz. Örneğin, aşağıdaki kod URL'leri "blog" ile başlayan bir çift uç nokta oluşturur ve bunları "tag-blog" olarak etiketler:
app.MapGet("/blog", Gravatar.WriteGravatar)
.CacheOutput(builder => builder.Tag("tag-blog"));
app.MapGet("/blog/post/{id}", Gravatar.WriteGravatar)
.CacheOutput(builder => builder.Tag("tag-blog"));
Aynı uç nokta çifti için etiket atamanın alternatif bir yolu, ile blog
başlayan uç noktalara uygulanan bir temel ilke tanımlamaktır:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Bir diğer alternatif de çağrısı MapGroup
yapmaktır:
var blog = app.MapGroup("blog")
.CacheOutput(builder => builder.Tag("tag-blog"));
blog.MapGet("/", Gravatar.WriteGravatar);
blog.MapGet("/post/{id}", Gravatar.WriteGravatar);
Yukarıdaki etiket atama örneklerinde her iki uç nokta da etiket tarafından tag-blog
tanımlanır. Ardından bu uç noktaların önbellek girdilerini şu etikete başvuran tek bir deyimle çıkarabilirsiniz:
app.MapPost("/purge/{tag}", async (IOutputCacheStore cache, string tag) =>
{
await cache.EvictByTagAsync(tag, default);
});
Bu kodla, gönderilen https://localhost:<port>/purge/tag-blog
bir HTTP POST isteği bu uç noktalar için önbellek girdilerini çıkaracaktır.
Tüm uç noktalar için tüm önbellek girdilerini çıkarmanın bir yolunu isteyebilirsiniz. Bunu yapmak için, aşağıdaki kodda olduğu gibi tüm uç noktalar için bir temel ilke oluşturun:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Bu temel ilke, önbellekteki her şeyi çıkarmak için "tag-all" etiketini kullanmanıza olanak tanır.
Kaynak kilitlemeyi devre dışı bırakma
Varsayılan olarak, önbellek damgalı ve gürleyen sürü riskini azaltmak için kaynak kilitleme etkinleştirilir. Daha fazla bilgi için bkz . Çıktı Önbelleğe Alma.
Kaynak kilitlemeyi devre dışı bırakmak için, aşağıdaki örnekte gösterildiği gibi bir ilke oluştururken SetLocking(false) öğesini çağırın:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder
.With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
.Tag("tag-blog"));
options.AddBasePolicy(builder => builder.Tag("tag-all"));
options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
options.AddPolicy("NoCache", builder => builder.NoCache());
options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});
Aşağıdaki örnek, bir uç nokta için kilitlememe ilkesini seçer:
app.MapGet("/nolock", Gravatar.WriteGravatar)
.CacheOutput("NoLock");
Sınırlar
aşağıdaki özellikleri OutputCacheOptions , tüm uç noktalara uygulanan sınırları yapılandırmanıza olanak sağlar:
- SizeLimit - En büyük önbellek depolama alanı boyutu. Bu sınıra ulaşıldığında, eski girdiler çıkarılana kadar yeni yanıtlar önbelleğe alınmaz. Varsayılan değer 100 MB'tır.
- MaximumBodySize - Yanıt gövdesi bu sınırı aşarsa önbelleğe alınmaz. Varsayılan değer 64 MB'tır.
- DefaultExpirationTimeSpan - İlke tarafından belirtilmediğinde geçerli olan süre sonu süresi. Varsayılan değer 60 saniyedir.
Önbellek depolama
IOutputCacheStore depolama için kullanılır. Varsayılan olarak ile MemoryCachekullanılır. Çıktı önbelleğe alma ile kullanılması önerilmez IDistributedCache . IDistributedCache
etiketleme için gereken atomik özelliklere sahip değildir. Redis gibi temel depolama mekanizmasında doğrudan bağımlılıkları kullanarak özel IOutputCacheStore uygulamalar oluşturmanızı öneririz. Veya .NET 8'de Redis cache için yerleşik desteği kullanın ..
Ayrıca bkz.
ASP.NET Core