我编写了一个基于 Azure BlobStorage 的自定义分布式缓存来优化页面速度。网站应该从缓存中传递缓存页面,直到缓存页面过期。这个实现应该像现有的 DistributedInMemoryCache、DistributedRedisCache 和 NCacheDistributedCache 一样工作。此处描述了操作方法https://docs.microsoft.com/de-de/aspnet/core/performance/caching/distributed?view=aspnetcore-5.0
我的问题是,在我的缓存中获取或设置的方法没有执行。
我将 IDistributedCache 实现为 DistributedBlobStorageCache 并在 ServiceCollection 扩展AddDistributedBlobStorageCache()的帮助下注册了它。所以票价这么好。
该操作具有上面的ResponseCacheAttribute,并且缓存配置文件在 Startup.cs 中设置。据我了解,系统配置是否正确,但执行分布式缓存的Get/GetAsync或Set/SetAsync方法。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddAntiforgery();
services.AddResponseCaching();
services.AddDistributedBlobStorageCache(options =>
{
options.ConnectionString = "<my connection string>";
});
services.AddResponseCompression();
services.AddHttpsRedirection(options => options.RedirectStatusCode = 301);
services.AddControllersWithViews(
options =>
{
options.RespectBrowserAcceptHeader = true;
options.CacheProfiles.Add(new KeyValuePair<string, CacheProfile>("test", new CacheProfile
{
Duration = 60
}));
// authorization filters
options.Filters.Add<AutoValidateAntiforgeryTokenAttribute>();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseResponseCaching();
app.UseResponseCompression();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
public static class BlobStorageCacheServiceCollectionExtensions
{
public static IServiceCollection AddDistributedBlobStorageCache(this IServiceCollection services, Action<BlobStorageCacheOptions> options)
{
if (options != default)
{
services.AddOptions();
services.Configure(options);
}
return services.AddSingleton<IDistributedCache, DistributedBlobStorageCache>();
}
}
public class BlobStorageCacheOptions : DistributedCacheEntryOptions
{
public string ConnectionString { get; set; }
}
public class DistributedBlobStorageCache : IDistributedCache
{
private readonly ILoggerFactory _loggerFactory;
private readonly BlobStorageCacheOptions _options;
public DistributedBlobStorageCache(ILoggerFactory loggerFactory, IOptions<BlobStorageCacheOptions> optionsAccessor)
{
_loggerFactory = loggerFactory;
_options = optionsAccessor?.Value;
}
public byte[] Get(string key)
{
return GetAsync(key).GetAwaiter().GetResult();
}
public async Task<byte[]> GetAsync(string key, CancellationToken token = new CancellationToken())
{
var repos = CreateRepository();
var cacheItem = await repos.GetAsync(key, token);
if (cacheItem == null || cacheItem.ContentBytes == null)
return Array.Empty<byte>();
return cacheItem.ContentBytes;
}
public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
{
SetAsync(key, value, options).GetAwaiter().GetResult();
}
public async Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options,
CancellationToken token = new CancellationToken())
{
var cacheItem = new CacheItem
{
ContentBytes = value,
Key = key,
UtcExpiry = options.AbsoluteExpiration.GetValueOrDefault(DateTimeOffset.UtcNow).DateTime
};
var repos = CreateRepository();
await repos.SaveAsync(cacheItem, token);
}
public void Refresh(string key)
{
// not needed, because we use no sliding expiration
}
public Task RefreshAsync(string key, CancellationToken token = new CancellationToken())
{
// not needed, because we use no sliding expiration
return Task.CompletedTask;
}
public void Remove(string key)
{
RemoveAsync(key).GetAwaiter().GetResult();
}
public async Task RemoveAsync(string key, CancellationToken token = new CancellationToken())
{
var repos = CreateRepository();
await repos.RemoveAsync(key, token);
}
private BlobStorageCacheRepository CreateRepository()
{
return new BlobStorageCacheRepository(_options.ConnectionString);
}
private class BlobStorageCacheRepository
{
public BlobStorageCacheRepository(string connectionString)
{
}
internal Task<CacheItem> GetAsync(string key, CancellationToken token)
{
// to implement
return Task.FromResult(new CacheItem());
}
internal Task SaveAsync(CacheItem item, CancellationToken token)
{
// to implement
return Task.CompletedTask;
}
internal Task RemoveAsync(string key, CancellationToken token)
{
// to implement
return Task.CompletedTask;
}
}
private class CacheItem
{
internal byte[] ContentBytes { get; set; }
internal string Key { get; set; }
internal DateTimeOffset UtcExpiry { get; set; }
}
}