public async Task Should_response_current_cache_if_there_is_error_but_StaleIfError_is_not_zero() { // Arrange _request.Headers.CacheControl = new CacheControlHeaderValue { MaxAge = TimeSpan.FromSeconds(10), Extensions = { new NameValueHeaderValue(WebApiExtensions.__cacheControl_flatwhite_force_refresh, "1") } }; var att = new Flatwhite.WebApi.OutputCacheAttribute { MaxAge = 10, IgnoreRevalidationRequest = true, StaleIfError = 2 }; _actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError); var objCacheItem = new WebApiCacheItem { MaxAge = 10, Key = CacheKey, StaleWhileRevalidate = 5, StoreId = _store.StoreId, StaleIfError = 2, CreatedTime = DateTime.UtcNow.AddSeconds(-5).AddMilliseconds(-1), Content = new byte[] { 0, 1, 2 }, ResponseMediaType = "application/json", ResponseCharSet = "utf-8", IgnoreRevalidationRequest = true }; _store.GetAsync(CacheKey).Returns(objCacheItem); // Action await att.OnActionExecutedAsync(_actionExecutedContext, CancellationToken.None); // Assert Assert.IsTrue(_actionExecutedContext.Response.IsSuccessStatusCode); await _store.DidNotReceive().SetAsync(Arg.Any <string>(), Arg.Any <object>(), Arg.Any <DateTimeOffset>()); }
private async Task <bool> AttemptToResponseTheCacheWhenError(HttpActionExecutedContext actionExecutedContext, IAsyncCacheStore cacheStore, string storedKey) { 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 = actionExecutedContext.Request.GetConfiguration().GetFlatwhiteCacheConfiguration().ResponseBuilder; var response = builder.GetResponse(actionExecutedContext.Request.Headers.CacheControl, cacheItem, actionExecutedContext.Request); if (response != null) { //NOTE: Override error response actionExecutedContext.Response = response; } return(true); } } return(false); }
/// <summary> /// Try to get the cache from etag and build the response if cache is available /// </summary> /// <param name="cacheControl"></param> /// <param name="request"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task <HttpResponseMessage> HandleAsync(CacheControlHeaderValue cacheControl, HttpRequestMessage request, CancellationToken cancellationToken) { if (request.Headers.IfNoneMatch != null) { // Etag format: fw-StoreId-HashedKey-Checksum var requestEtags = request.Headers.IfNoneMatch.Where(t => t.Tag != null && t.Tag.StartsWith("\"fw-")).ToList(); if (requestEtags.Count > 0) { foreach (var etag in requestEtags) { var etagString = etag.Tag.Trim('"'); var index = etagString.IndexOf("-", 4, StringComparison.Ordinal); var storeIdString = index > 0 ? etagString.Substring(3, index - 3) : "0"; index = etagString.LastIndexOf("-", StringComparison.Ordinal); int storeId; IAsyncCacheStore cacheStore = null; if (int.TryParse(storeIdString, out storeId)) { cacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(storeId) ?? Global.CacheStoreProvider.GetAsyncCacheStore(); } if (cacheStore != null && index > 0) { var hashedKey = etagString.Substring(0, index); var checkSum = etagString.Substring(index + 1); var cacheItem = (await cacheStore.GetAsync(hashedKey)) as WebApiCacheItem; if (cacheItem != null && cacheItem.Checksum == checkSum) { request.Properties[WebApiExtensions.__webApi_etag_matched] = true; } return(_builder.GetResponse(cacheControl, cacheItem, request)); } } } } return(null); }