public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
if (ShouldIgnoreCache(actionExecutedContext.Request.Headers.CacheControl, actionExecutedContext.Request))
{
return;
}
if ((actionExecutedContext.ActionContext.Response == null || !actionExecutedContext.ActionContext.Response.IsSuccessStatusCode) && StaleIfError == 0)
{
return; // Early return
}
var cacheControl = actionExecutedContext.Request.Headers.CacheControl;
if (cacheControl?.Extensions != null && cacheControl.Extensions.Any(x => x.Name == WebApiExtensions.__cacheControl_flatwhite_force_refresh))
{
var entry = cacheControl.Extensions.First(x => x.Name == WebApiExtensions.__cacheControl_flatwhite_force_refresh);
cacheControl.Extensions.Remove(entry);
}
ApplyCacheHeaders(actionExecutedContext.ActionContext.Response, actionExecutedContext.Request);
var storedKey = (string)actionExecutedContext.Request.Properties[Global.__flatwhite_outputcache_key];
var cacheStore = (IAsyncCacheStore)actionExecutedContext.Request.Properties[Global.__flatwhite_outputcache_store];
if (actionExecutedContext.ActionContext.Response == null || !actionExecutedContext.ActionContext.Response.IsSuccessStatusCode)
{
var cacheItem = await cacheStore.GetAsync(storedKey).ConfigureAwait(false) as WebApiCacheItem;
if (cacheItem != null && StaleIfError > 0)
{
var builder = (ICacheResponseBuilder)actionExecutedContext.Request.Properties[WebApiExtensions.__webApi_outputcache_response_builder];
var response = builder.GetResponse(actionExecutedContext.Request.Headers.CacheControl, cacheItem, actionExecutedContext.Request);
if (response != null)
{
//NOTE: Override error response
actionExecutedContext.Response = response;
}
return;
}
}
var responseContent = actionExecutedContext.Response.Content;
if (responseContent != null)
{
var cacheItem = new WebApiCacheItem
{
Key = storedKey,
Content = await responseContent.ReadAsByteArrayAsync().ConfigureAwait(false),
ResponseMediaType = responseContent.Headers.ContentType.MediaType,
ResponseCharSet = responseContent.Headers.ContentType.CharSet,
StoreId = cacheStore.StoreId,
StaleWhileRevalidate = StaleWhileRevalidate,
MaxAge = MaxAge,
CreatedTime = DateTime.UtcNow,
IgnoreRevalidationRequest = IgnoreRevalidationRequest,
StaleIfError = StaleIfError,
AutoRefresh = AutoRefresh
};
var strategy = (ICacheStrategy)actionExecutedContext.Request.Properties[Global.__flatwhite_outputcache_strategy];
var invocation = GetInvocation(actionExecutedContext.ActionContext);
var context = GetInvocationContext(actionExecutedContext.ActionContext);
var changeMonitors = strategy.GetChangeMonitors(invocation, context);
CreatePhoenix(invocation, cacheItem, actionExecutedContext.Request);
foreach (var mon in changeMonitors)
{
mon.CacheMonitorChanged += state =>
{
RefreshCache(storedKey);
};
}
actionExecutedContext.Response.Headers.ETag = new EntityTagHeaderValue($"\"{cacheItem.Key}-{cacheItem.Checksum}\"");
var absoluteExpiration = DateTime.UtcNow.AddSeconds(MaxAge + Math.Max(StaleWhileRevalidate, StaleIfError));
await cacheStore.SetAsync(cacheItem.Key, cacheItem, absoluteExpiration).ConfigureAwait(false);
}
}