/// <summary>
        /// Adds an Entry to the cache.
        /// <para/>
        /// This method can handle already existent items.
        /// </summary>
        /// <param name="key">The key of the response.</param>
        /// <param name="value">The response.</param>
        protected void AddStringResponseEntry(string key, ResponseCacheEntry <string> value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            var old = StringResponses[key];

            if (old)
            {
                RemoveStringResponseEntry(key, old);
            }

            using (StringResponseLock.LockWrite())
            {
                CurrentStringResponseCacheSize += (ulong)value.Response.Length;
                StringResponses[key]            = value;
            }
        }
        /// <summary>
        /// Sets a response to the cache.
        /// </summary>
        /// <param name="key">The key of the response.</param>
        /// <param name="response">The response.</param>
        /// <param name="refreshTime">The lifetime of this entry. If null this entry doesn't have to be refreshed.</param>
        public void SetCachedStringResponse(string key, string response, TimeSpan?refreshTime = null)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (MaximumStringResponseCacheSize.HasValue && (ulong)response.Length > MaximumStringResponseCacheSize.Value)
            {
                Logger.LogDebugExcept($"The given response for '{key}' is to big to be cached.");
                return;
            }

            using (StringResponseLock.LockWrite())
            {
                if (MaximumStringResponseCacheSize.HasValue && CurrentStringResponseCacheSize + (ulong)response.Length > MaximumStringResponseCacheSize.Value)
                {
                    MakeRoom((ulong)response.Length);
                }

                ResponseCacheEntry <string> entry = new ResponseCacheEntry <string>()
                {
                    LastUpdatedDateTime = DateTime.UtcNow,
                    RefreshTime         = refreshTime,
                    Response            = response
                };

                AddStringResponseEntry(key, entry);
            }
        }
        /// <summary>
        /// 转储并缓存响应
        /// </summary>
        /// <param name="executingContext"></param>
        /// <param name="next"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        protected async Task <ResponseCacheEntry?> DumpAndCacheResponseAsync(ResourceExecutingContext executingContext, ResourceExecutionDelegate next, string key)
        {
            var response     = executingContext.HttpContext.Response;
            var originalBody = response.Body;

            using var dumpStream = executingContext.HttpContext.RequestServices.GetRequiredService <IResponseDumpStreamFactory>().Create(Context.DumpStreamCapacity);

            ResponseCacheEntry      cacheEntry = null !;
            ResourceExecutedContext executedContext;

            try
            {
                response.Body = dumpStream;

                CachingDiagnostics.NoCachingFounded(key, executingContext, Context);

                executedContext = await next();

                dumpStream.Position = 0;
                await dumpStream.CopyToAsync(originalBody);

                cacheEntry = new ResponseCacheEntry(response.ContentType, dumpStream.ToArray().AsMemory(), Context.Duration);
            }
            finally
            {
                response.Body = originalBody;
            }

            return(await CheckAndStoreCacheAsync(executingContext, executedContext, key, cacheEntry));
        }
示例#4
0
 public Task SetAsync(string key, ResponseCacheEntry entry, TimeSpan expiration)
 {
     _cache.Set(key, entry,
                new MemoryCacheEntryOptions().SetAbsoluteExpiration(expiration));
     _keys.TryAdd(key, key);
     return(Task.CompletedTask);
 }
示例#5
0
        public async Task ParallelGetSetResponseEntry()
        {
            //注意:redis所在系统时间与运行测试所在系统时间有误差时,会导致测试无法通过
            var duration = 1;

            var tasks = Enumerable.Range(0, 500).Select(async index =>
            {
                var key         = $"ResponseCacheTestKey_{index}";
                var contentType = $"application/json; charset=utf-8; idx={index}";
                var body        = Encoding.UTF8.GetBytes($"{SimResponseContent}_{index}");
                var entry       = new ResponseCacheEntry(contentType, body, duration);

                await ResponseCache.SetAsync(key, entry, CancellationToken.None);

                var cachedEntry = await ResponseCache.GetAsync(key, CancellationToken.None);

                TestUtil.EntryEquals(entry, cachedEntry);

                await Task.Delay(TimeSpan.FromSeconds(duration + 1));

                cachedEntry = await ResponseCache.GetAsync(key, CancellationToken.None);

                Assert.IsNull(cachedEntry);
            });

            await Task.WhenAll(tasks);
        }
        public IResponseCacheEntry Get(string key)
        {
            try
            {
                CacheEntry cacheEntry = GetCacheEntry(key);

                if (cacheEntry is VaryByKeysCacheEntry)
                {
                    VaryByKeysCacheEntry varyByKeysCacheEntry = (VaryByKeysCacheEntry)cacheEntry;
                    return(new CachedVaryByRules()
                    {
                        Headers = new StringValues(varyByKeysCacheEntry.Headers),
                        QueryKeys = new StringValues(varyByKeysCacheEntry.QueryKeys),
                        VaryByKeyPrefix = varyByKeysCacheEntry.VaryByKeyPrefix
                    });
                }

                if (cacheEntry is ResponseCacheEntry)
                {
                    ResponseCacheEntry responseCacheEntry = (ResponseCacheEntry)cacheEntry;
                    return(new CachedResponse()
                    {
                        Body = new MemoryStream(responseCacheEntry.Body),
                        Headers = new HeaderDictionary(responseCacheEntry.HeaderDictionary.ToDictionary(x => x.Key, x => new StringValues(x.Value))),
                        StatusCode = responseCacheEntry.StatusCode,
                        Created = responseCacheEntry.Created
                    });
                }
            }
            catch
            {
            }

            return(null);
        }
示例#7
0
 public Task <bool> OnResponseWritingAsync(ActionContext actionContext,
                                           ResponseCacheEntry entry,
                                           OnResponseWritingDelegate next)
 {
     actionContext.HttpContext.Response.Headers.Add(_headerKey, _headerValue);
     return(next(actionContext, entry));
 }
示例#8
0
        protected async Task <bool> WriteCacheToResponseAsync(ActionContext context, ResponseCacheEntry cacheEntry)
        {
            CachingDiagnostics.ResponseFromCache(context, cacheEntry, Context);
            context.HttpContext.Response.ContentType = cacheEntry.ContentType;
            await context.HttpContext.Response.BodyWriter.WriteAsync(cacheEntry.Body, context.HttpContext.RequestAborted);

            return(true);
        }
 /// <inheritdoc cref="ResponseFromCacheEventData"/>
 public void ResponseFromCache(ActionContext actionContext, ResponseCacheEntry cacheEntry, ResponseCachingContext context)
 {
     if (DiagnosticSource != null &&
         DiagnosticSource.IsEnabled(ResponseFromCacheEventData.EventName))
     {
         DiagnosticSource.Write(ResponseFromCacheEventData.EventName, new ResponseFromCacheEventData(actionContext, cacheEntry, context));
     }
 }
示例#10
0
        /// <summary>
        /// 执行请求
        /// </summary>
        /// <returns></returns>
        private async Task <object> ExecRequestAsync()
        {
            using (var cancellation = this.CreateLinkedTokenSource())
            {
                var cacheAttribute = this.ApiActionDescriptor.Cache;
                var cacheProvider  = this.HttpApiConfig.ResponseCacheProvider;

                var cacheKey    = default(string);
                var cacheResult = ResponseCacheResult.NoValue;
                var cacheEnable = cacheAttribute != null && cacheProvider != null;

                if (cacheEnable == true)
                {
                    cacheKey = await cacheAttribute.GetCacheKeyAsync(this).ConfigureAwait(false);

                    cacheResult = await cacheProvider.GetAsync(cacheKey).ConfigureAwait(false);
                }

                if (cacheResult.HasValue == true)
                {
                    this.ResponseMessage = cacheResult.Value.ToResponseMessage(this.RequestMessage, cacheProvider.Name);
                }
                else
                {
                    var completionOption = this.ApiActionDescriptor.Return.DataType.IsHttpResponseWrapper ?
                                           HttpCompletionOption.ResponseHeadersRead :
                                           HttpCompletionOption.ResponseContentRead;

                    this.ResponseMessage = await this.HttpApiConfig.HttpClient
                                           .SendAsync(this.RequestMessage, completionOption, cancellation.Token)
                                           .ConfigureAwait(false);

                    if (cacheEnable == true)
                    {
                        var cacheEntry = await ResponseCacheEntry.FromResponseMessageAsync(this.ResponseMessage).ConfigureAwait(false);

                        await cacheProvider.SetAsync(cacheKey, cacheEntry, cacheAttribute.Expiration).ConfigureAwait(false);
                    }
                }

                var result = await this.ApiActionDescriptor.Return.Attribute
                             .GetTaskResult(this)
                             .ConfigureAwait(false);

                ApiValidator.ValidateReturnValue(result, this.HttpApiConfig.UseReturnValuePropertyValidate);
                return(result);
            }
        }
示例#11
0
        /// <summary>
        /// 检查并保存缓存
        /// </summary>
        /// <param name="executingContext"></param>
        /// <param name="executedContext"></param>
        /// <param name="key"></param>
        /// <param name="cacheEntry"></param>
        /// <returns></returns>
        protected async Task <ResponseCacheEntry?> CheckAndStoreCacheAsync(ResourceExecutingContext executingContext,
                                                                           ResourceExecutedContext executedContext,
                                                                           string key,
                                                                           ResponseCacheEntry cacheEntry)
        {
            if (Context.CacheDeterminer.CanCaching(executedContext, cacheEntry))
            {
                if (cacheEntry.Body.Length <= Context.MaxCacheableResponseLength)
                {
                    return(await Context.Interceptors.OnCacheStoringAsync(executingContext, key, cacheEntry, StoreCacheAsync));
                }
                else
                {
                    CachingDiagnostics.CacheBodyTooLarge(key, cacheEntry.Body, Context.MaxCacheableResponseLength, executingContext, Context);
                }
            }

            return(null);
        }
示例#12
0
        public async Task GetSetResponseEntry()
        {
            //注意:redis所在系统时间与运行测试所在系统时间有误差时,会导致测试无法通过
            var duration    = 1;
            var key         = "ResponseCacheTestKey";
            var contentType = "application/json; charset=utf-8";
            var body        = Encoding.UTF8.GetBytes(SimResponseContent);
            var entry       = new ResponseCacheEntry(contentType, body, duration);

            await ResponseCache.SetAsync(key, entry, CancellationToken.None);

            var cachedEntry = await ResponseCache.GetAsync(key, CancellationToken.None);

            Assert.IsNotNull(cachedEntry, "获取到缓存为空,redis所在系统时间与运行测试所在系统时间有误差时,可能会导致测试无法通过");

            TestUtil.EntryEquals(entry, cachedEntry);

            await Task.Delay(TimeSpan.FromSeconds(duration + 1));

            cachedEntry = await ResponseCache.GetAsync(key, CancellationToken.None);

            Assert.IsNull(cachedEntry);
        }
        /// <summary>
        /// Removes an entry from the cache.
        /// <para/>
        /// This method can handle non-existent items.
        /// </summary>
        /// <param name="key">The key of the entry.</param>
        /// <param name="value">The response if already retrieved. If null, the response will be retrieved automatically.</param>
        protected void RemoveStringResponseEntry(string key, ResponseCacheEntry <string> value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (!value)
            {
                value = StringResponses[key];
            }

            if (!value) // if it couldn't be retrieved.
            {
                return;
            }

            using (StringResponseLock.LockWrite())
            {
                CurrentStringResponseCacheSize -= (ulong)value.Response.Length;
                StringResponses.Remove(key);
            }
        }
        /// <summary>
        /// Removes a collection of entries from the cache.
        /// <para/>
        /// This method can handle non-existent items.
        /// </summary>
        /// <param name="keys">The keys of the entries.</param>
        protected void RemoveStringResponseEntries(ICollection <string> keys)
        {
            if (keys == null)
            {
                throw new ArgumentNullException(nameof(keys));
            }

            using (StringResponseLock.LockWrite())
            {
                foreach (string key in keys)
                {
                    ResponseCacheEntry <string> value = StringResponses[key];

                    if (!value) // if the value couldn't be retrieved.
                    {
                        continue;
                    }

                    CurrentStringResponseCacheSize -= (ulong)value.Response.Length;
                    StringResponses.Remove(key);
                }
            }
        }
示例#15
0
 public Task <ResponseCacheEntry> OnCacheStoringAsync(ActionContext actionContext, string key, ResponseCacheEntry entry, OnCacheStoringDelegate <ActionContext> next)
 {
     OnCacheStoringCallCount++;
     return(Task.FromResult <ResponseCacheEntry>(null));
 }
示例#16
0
 /// <summary>
 /// 设置响应实体到缓存
 /// </summary>
 /// <param name="key">键</param>
 /// <param name="entry">缓存实体</param>
 /// <param name="expiration">有效时间</param>
 /// <returns></returns>
 public async Task SetAsync(string key, ResponseCacheEntry entry, TimeSpan expiration)
 {
     var cacheProvider = _serviceProvider.GetService(typeof(IEasyCachingProvider)) as IEasyCachingProvider;
     await cacheProvider.SetAsync(key, entry, expiration);
 }
 public static void EntryEquals(ResponseCacheEntry entry1, ResponseCacheEntry entry2)
 {
     Assert.AreEqual(entry1.ContentType, entry2.ContentType);
     Assert.AreEqual(entry1.Body.Length, entry2.Body.Length);
     Assert.IsTrue(Enumerable.SequenceEqual(entry1.Body.ToArray(), entry2.Body.ToArray()));
 }
示例#18
0
 /// <inheritdoc/>
 public bool CanCaching(ResourceExecutedContext context, ResponseCacheEntry cacheEntry)
 => context.HttpContext.Response.StatusCode == StatusCodes.Status200OK;
示例#19
0
 protected Task <bool> WriteCacheToResponseWithInterceptorAsync(ActionContext context, ResponseCacheEntry cacheEntry)
 {
     return(Context.Interceptors.OnResponseWritingAsync(context, cacheEntry, WriteCacheToResponseAsync));
 }
示例#20
0
        private async Task <ResponseCacheEntry?> InternalStoreCacheAsync(ActionContext actionContext, string key, ResponseCacheEntry cacheEntry)
        {
            await ResponseCache.SetAsync(key, cacheEntry, actionContext.HttpContext.RequestAborted);

            return(cacheEntry);
        }
 /// <inheritdoc cref="ResponseFromCacheEventData"/>
 public ResponseFromCacheEventData(ActionContext actionContext, ResponseCacheEntry cacheEntry, ResponseCachingContext context) : base(context)
 {
     ActionContext = actionContext;
     CacheEntry    = cacheEntry;
 }
示例#22
0
 public Task <bool> OnResponseWritingAsync(ActionContext actionContext, ResponseCacheEntry entry, OnResponseWritingDelegate next)
 {
     OnResponseWritingCallCount++;
     return(next(actionContext, entry));
 }
示例#23
0
 public Task <ResponseCacheEntry> OnCacheStoringAsync(ActionContext actionContext, string key, ResponseCacheEntry entry, OnCacheStoringDelegate <ActionContext> next)
 {
     OnCacheStoringCallCount++;
     return(next(actionContext, key, entry));
 }
示例#24
0
 /// <summary>
 /// 设置响应实体到缓存
 /// </summary>
 /// <param name="key">键</param>
 /// <param name="entry">缓存实体</param>
 /// <param name="expiration">有效时间</param>
 /// <returns></returns>
 public virtual Task SetAsync(string key, ResponseCacheEntry entry, TimeSpan expiration)
 {
     this.cache.Set(key, entry, DateTimeOffset.Now.Add(expiration));
     return(Task.CompletedTask);
 }
示例#25
0
 public Task <bool> OnResponseWritingAsync(ActionContext actionContext, ResponseCacheEntry entry, OnResponseWritingDelegate next)
 {
     OnResponseWritingCallCount++;
     return(Task.FromResult(true));
 }
示例#26
0
 protected Task <ResponseCacheEntry?> StoreCacheAsync(ActionContext actionContext, string key, ResponseCacheEntry cacheEntry)
 {
     return(Context.Interceptors.OnCacheStoringAsync(actionContext, key, cacheEntry, _onCacheStoringDelegate));
 }
 public Task SetAsync(string key, ResponseCacheEntry entry, CancellationToken cancellationToken)
 {
     _caches.AddOrUpdate(key, entry, (_, _) => entry);
     return(Task.CompletedTask);
 }