예제 #1
0
    internal async Task <bool> TryServeFromCacheAsync(OutputCacheContext cacheContext, IReadOnlyList <IOutputCachePolicy> policies)
    {
        CreateCacheKey(cacheContext);

        // Locking cache lookups by default
        // TODO: should it be part of the cache implementations or can we assume all caches would benefit from it?
        // It makes sense for caches that use IO (disk, network) or need to deserialize the state but could also be a global option

        var cacheEntry = await _outputCacheEntryDispatcher.ScheduleAsync(cacheContext.CacheKey, (Store : _store, CacheContext : cacheContext), static async (key, state) => await OutputCacheEntryFormatter.GetAsync(key, state.Store, state.CacheContext.HttpContext.RequestAborted));
예제 #2
0
    private async Task InvokeAwaited(HttpContext httpContext, IReadOnlyList <IOutputCachePolicy> policies)
    {
        var context = new OutputCacheContext {
            HttpContext = httpContext
        };

        // Add IOutputCacheFeature
        AddOutputCacheFeature(context);

        try
        {
            foreach (var policy in policies)
            {
                await policy.CacheRequestAsync(context, httpContext.RequestAborted);
            }

            // Should we attempt any caching logic?
            if (context.EnableOutputCaching)
            {
                // Can this request be served from cache?
                if (context.AllowCacheLookup)
                {
                    if (await TryServeFromCacheAsync(context, policies))
                    {
                        return;
                    }
                }

                // Should we store the response to this request?
                if (context.AllowCacheStorage)
                {
                    // It is also a pre-condition to reponse locking

                    var executed = false;

                    if (context.AllowLocking)
                    {
                        var cacheEntry = await _requestDispatcher.ScheduleAsync(context.CacheKey, key => ExecuteResponseAsync());

                        // The current request was processed, nothing more to do
                        if (executed)
                        {
                            return;
                        }

                        // If the result was processed by another request, try to serve it from cache entry (no lookup)
                        if (await TryServeCachedResponseAsync(context, cacheEntry, policies))
                        {
                            return;
                        }

                        // If the cache entry couldn't be served, continue to processing the request as usual
                    }

                    await ExecuteResponseAsync();

                    async Task <OutputCacheEntry?> ExecuteResponseAsync()
                    {
                        // Hook up to listen to the response stream
                        ShimResponseStream(context);

                        try
                        {
                            await _next(httpContext);

                            // The next middleware might change the policy
                            foreach (var policy in policies)
                            {
                                await policy.ServeResponseAsync(context, httpContext.RequestAborted);
                            }

                            // If there was no response body, check the response headers now. We can cache things like redirects.
                            StartResponse(context);

                            // Finalize the cache entry
                            await FinalizeCacheBodyAsync(context);

                            executed = true;
                        }
                        finally
                        {
                            UnshimResponseStream(context);
                        }

                        return(context.CachedResponse);
                    }

                    return;
                }
            }

            await _next(httpContext);
        }
        finally
        {
            RemoveOutputCacheFeature(httpContext);
        }
    }