private async Task HandleCachedAttribute(
            CachedAttribute attribute, MethodInfo actionMethod,
            ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (UserAgentSpecifiedNoCache(context.HttpContext.Request))
            {
                await next();

                return;
            }

            var scopeValue        = _cacheParametersResolver.ResolveScopeValue(attribute.ScopeName, context);
            var outputContentType = actionMethod.GetCustomAttribute <ProducesAttribute>()?.ContentTypes.First()
                                    ?? RawActionResult.JsonContentType;
            var methodParameters = new CacheMethodParameters(
                actionMethod.GetUniqueIdentifier(),
                attribute.ScopeName,
                scopeValue,
                context.ActionArguments,
                outputContentType,
                attribute.ExpireAfterTimeSpan ?? _cacheParametersResolver.DefaultExpiration,
                attribute.SlidingExpiration);
            var cacheGetResult = await _cacheAdapter.GetOrUpdate(methodParameters, () => OnCacheMiss(next));

            if (cacheGetResult.Hit)
            {
                context.Result = cacheGetResult.ValueFromCache;
            }
        }
Beispiel #2
0
        private async Task CacheMethodResult(
            CacheMethodParameters parameters, string statusCodeFieldName,
            string payloadFieldName, string contentTypeFieldName, IActionResult result)
        {
            var entries = new List <HashEntry>();

            switch (result)
            {
            // methods that does not return an IActionResult might not have the status code field populated:
            case ObjectResult objectResult:
            {
                var statusCode             = objectResult.StatusCode ?? (int)HttpStatusCode.OK;
                var contentTypeFormatterId = parameters.OutputContentType.Split(';')[0];
                if (objectResult.Value != null)
                {
                    var payload = await _serializationHelper.Serialize(contentTypeFormatterId, objectResult.Value);

                    entries.Add(new HashEntry(payloadFieldName, payload));
                    entries.Add(new HashEntry(contentTypeFieldName, parameters.OutputContentType));
                }
                entries.Add(new HashEntry(statusCodeFieldName, statusCode));
                break;
            }

            case StatusCodeResult statusCodeResult:
            {
                var statusCode = statusCodeResult.StatusCode;
                entries.Add(new HashEntry(statusCodeFieldName, statusCode));
                break;
            }

            default:
                throw new UnsupportedContentTypeException("unsupported WebApi method result type!");
            }

            var key      = GetCacheKey(parameters.MethodName, parameters.ScopeName, parameters.ScopeValue);
            var database = _redisConnectionMultiplexer.GetDatabase();
            await database.HashSetAsync(key, entries.ToArray());

            if (parameters.ExpirationTime.HasValue)
            {
                await database.KeyExpireAsync(key, parameters.ExpirationTime.Value);
            }
        }
Beispiel #3
0
        public async Task <CacheGetResult> GetOrUpdate(
            CacheMethodParameters parameters, Func <Task <IActionResult> > cacheMissResolver)
        {
            var database = _redisConnectionMultiplexer.GetDatabase();
            var key      = GetCacheKey(parameters.MethodName, parameters.ScopeName, parameters.ScopeValue);

            var(statusCodeFieldName, payloadFieldName, contentTypeFieldName) =
                GetCacheParametersFieldNames(parameters);
            var cached = await database.HashGetAsync(key, new RedisValue[]
            {
                statusCodeFieldName, payloadFieldName, contentTypeFieldName
            });

            var statusCode  = cached[0];
            var payload     = cached[1];
            var contentType = cached[2];

            if (!statusCode.HasValue)
            {
                var newValue = await cacheMissResolver();

                if (newValue != null)
                {
                    await CacheMethodResult(parameters, statusCodeFieldName, payloadFieldName, contentTypeFieldName,
                                            newValue);
                }

                return(new CacheGetResult(false, null));
            }

            if (parameters.ExpirationTime.HasValue && parameters.IsSlidingExpiration)
            {
                await database.KeyExpireAsync(key, parameters.ExpirationTime.Value);
            }

            ActionResult result = new RawActionResult((int)statusCode, payload, contentType,
                                                      new Dictionary <string, string>
            {
                ["x-served-from-cache"] = "true"
            });


            return(new CacheGetResult(true, result));
        }
Beispiel #4
0
        GetCacheParametersFieldNames(CacheMethodParameters parameters)
        {
            var parametersHash = _serializationHelper.ComputeHash(parameters.Parameters);

            return($"{parametersHash}:statusCode", $"{parametersHash}:payload", $"{parametersHash}:contentType");
        }