/// <summary>
        /// Registers the output caching service with the dependency injection system.
        /// </summary>
        public static void AddOutputCaching(this IServiceCollection services)
        {
            var options = new OutputCacheOptions();

            services.AddSingleton(options);
            services.AddSingleton <IOutputCachingService, OutputCachingService>();
        }
예제 #2
0
    public async Task ServesFreshContent_If_ResponseExpired(string method)
    {
        var options = new OutputCacheOptions
        {
            DefaultExpirationTimeSpan = TimeSpan.FromMicroseconds(100)
        };

        var builders = TestUtils.CreateBuildersWithOutputCaching(options: options);

        foreach (var builder in builders)
        {
            using var host = builder.Build();

            await host.StartAsync();

            using var server = host.GetTestServer();
            var client          = server.CreateClient();
            var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, ""));

            await Task.Delay(1);

            var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, ""));

            await AssertFreshResponseAsync(initialResponse, subsequentResponse);
        }
    }
예제 #3
0
    public async Task ServesCachedContent_If_Authorization_HeaderExists(string method)
    {
        var options = new OutputCacheOptions();

        var builders = TestUtils.CreateBuildersWithOutputCaching(options: options);

        // This is added after the DefaultPolicy which disables caching for authenticated requests
        options.AddBasePolicy(b => b.AddPolicy <AllowTestPolicy>());

        foreach (var builder in builders)
        {
            using var host = builder.Build();

            await host.StartAsync();

            using var server = host.GetTestServer();
            var client = server.CreateClient();
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("abc");
            var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, ""));

            var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, ""));

            await AssertCachedResponseAsync(initialResponse, subsequentResponse);
        }
    }
예제 #4
0
    public async Task ServesFreshContent_IfVaryHeader_Mismatches()
    {
        var options = new OutputCacheOptions();

        options.AddBasePolicy(b => b.VaryByHeader(HeaderNames.From).Build());

        var builders = TestUtils.CreateBuildersWithOutputCaching(options: options);

        foreach (var builder in builders)
        {
            using var host = builder.Build();

            await host.StartAsync();

            using var server = host.GetTestServer();
            var client = server.CreateClient();
            client.DefaultRequestHeaders.From = "*****@*****.**";
            var initialResponse = await client.GetAsync("");

            client.DefaultRequestHeaders.From = "*****@*****.**";
            var subsequentResponse = await client.GetAsync("");

            await AssertFreshResponseAsync(initialResponse, subsequentResponse);
        }
    }
예제 #5
0
    internal static OutputCacheMiddleware CreateTestMiddleware(
        RequestDelegate?next                = null,
        IOutputCacheStore?cache             = null,
        OutputCacheOptions?options          = null,
        TestSink?testSink                   = null,
        IOutputCacheKeyProvider?keyProvider = null
        )
    {
        if (next == null)
        {
            next = httpContext => Task.CompletedTask;
        }
        if (cache == null)
        {
            cache = new TestOutputCache();
        }
        if (options == null)
        {
            options = new OutputCacheOptions();
        }
        if (keyProvider == null)
        {
            keyProvider = new OutputCacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
        }

        return(new OutputCacheMiddleware(
                   next,
                   Options.Create(options),
                   testSink == null ? NullLoggerFactory.Instance : new TestLoggerFactory(testSink, true),
                   cache,
                   keyProvider));
    }
        /// <summary>
        /// Registers the output caching service with the dependency injection system.
        /// </summary>
        public static void AddOutputCaching(this IServiceCollection services, Action <OutputCacheOptions> outputCacheOptions)
        {
            var options = new OutputCacheOptions();

            outputCacheOptions(options);

            services.AddOutputCaching(options);
        }
예제 #7
0
    internal OutputCacheKeyProvider(ObjectPoolProvider poolProvider, IOptions <OutputCacheOptions> options)
    {
        ArgumentNullException.ThrowIfNull(poolProvider);
        ArgumentNullException.ThrowIfNull(options);

        _builderPool = poolProvider.CreateStringBuilderPool();
        _options     = options.Value;
    }
        public string RemoveDonutHoleWrappers(string content, ControllerContext filterContext, OutputCacheOptions options)
        {
            //if (
            //    filterContext.IsChildAction &&
            //    (options & OutputCacheOptions.ReplaceDonutsInChildActions) != OutputCacheOptions.ReplaceDonutsInChildActions)
            //{
            //    return content;
            //}

            return DonutHoles.Replace(content, match => match.Groups[2].Value);
        }
    public async Task Attribute_CreatesNamedPolicy()
    {
        var options = new OutputCacheOptions();

        options.AddPolicy("MyPolicy", b => b.Expire(TimeSpan.FromSeconds(42)));

        var context = TestUtils.CreateTestContext(options: options);

        var attribute = OutputCacheMethods.GetAttribute(nameof(OutputCacheMethods.PolicyName));
        await attribute.BuildPolicy().CacheRequestAsync(context, cancellation: default);

        Assert.True(context.EnableOutputCaching);
        Assert.Equal(42, context.ResponseExpirationTimeSpan?.TotalSeconds);
    }
    public async Task BuildPolicy_CacheReturnsDefault()
    {
        // Each predicate should override the duration from the first base policy
        var options = new OutputCacheOptions();

        options.AddBasePolicy(build => build.Cache());

        var context = TestUtils.CreateUninitializedContext(options: options);

        foreach (var policy in options.BasePolicies)
        {
            await policy.CacheRequestAsync(context, default);
        }

        Assert.True(context.EnableOutputCaching);
    }
    public async Task BuildPolicy_AddsCustomPolicy()
    {
        var options  = new OutputCacheOptions();
        var name     = "MyPolicy";
        var duration = 42;

        options.AddPolicy(name, b => b.Expire(TimeSpan.FromSeconds(duration)));

        var context = TestUtils.CreateUninitializedContext(options: options);

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.AddPolicy(new NamedPolicy(name)).Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Equal(duration, context.ResponseExpirationTimeSpan?.TotalSeconds);
    }
    public async Task BuildPolicy_NoDefaultWithFalsePredicate()
    {
        // Each predicate should override the duration from the first base policy
        var options = new OutputCacheOptions();

        options.AddBasePolicy(build => build.With(c => false).Expire(TimeSpan.FromSeconds(2)));

        var context = TestUtils.CreateUninitializedContext(options: options);

        foreach (var policy in options.BasePolicies)
        {
            await policy.CacheRequestAsync(context, default);
        }

        Assert.False(context.EnableOutputCaching);
        Assert.NotEqual(2, context.ResponseExpirationTimeSpan?.TotalSeconds);
    }
    public async Task BuildPolicy_ChecksWithPredicate(int source, int expected)
    {
        // Each predicate should override the duration from the first base policy
        var options = new OutputCacheOptions();

        options.AddBasePolicy(build => build.Expire(TimeSpan.FromSeconds(1)));
        options.AddBasePolicy(build => build.With(c => source == 1).Expire(TimeSpan.FromSeconds(2)));
        options.AddBasePolicy(build => build.With(c => source == 2).Expire(TimeSpan.FromSeconds(3)));

        var context = TestUtils.CreateUninitializedContext(options: options);

        foreach (var policy in options.BasePolicies)
        {
            await policy.CacheRequestAsync(context, default);
        }

        Assert.True(context.EnableOutputCaching);
        Assert.Equal(expected, context.ResponseExpirationTimeSpan?.TotalSeconds);
    }
예제 #14
0
    public async Task ProfilePolicy_UsesNamedProfile()
    {
        var options = new OutputCacheOptions();

        options.AddPolicy("enabled", EnableCachePolicy.Enabled);
        options.AddPolicy("disabled", EnableCachePolicy.Disabled);
        var context = TestUtils.CreateUninitializedContext(options: options);

        IOutputCachePolicy policy = new NamedPolicy("enabled");

        await policy.CacheRequestAsync(context, default);

        Assert.True(context.EnableOutputCaching);

        policy = new NamedPolicy("disabled");

        await policy.CacheRequestAsync(context, default);

        Assert.False(context.EnableOutputCaching);
    }
        public string ReplaceDonutHoleContent(string content, ControllerContext filterContext, OutputCacheOptions options)
        {
            //if (
            //    filterContext.IsChildAction &&
            //    (options & OutputCacheOptions.ReplaceDonutsInChildActions) != OutputCacheOptions.ReplaceDonutsInChildActions)
            //{
            //    return content;
            //}

            return DonutHoles.Replace(content, match =>
            {
                var actionSettings = _actionSettingsSerialiser.Deserialise(match.Groups[1].Value);

                return InvokeAction(
                    filterContext.Controller,
                    actionSettings.ActionName,
                    actionSettings.ControllerName,
                    actionSettings.RouteValues
                );
            });
        }
예제 #16
0
    // for testing
    internal OutputCacheMiddleware(
        RequestDelegate next,
        IOptions <OutputCacheOptions> options,
        ILoggerFactory loggerFactory,
        IOutputCacheStore cache,
        IOutputCacheKeyProvider keyProvider)
    {
        ArgumentNullException.ThrowIfNull(next);
        ArgumentNullException.ThrowIfNull(options);
        ArgumentNullException.ThrowIfNull(loggerFactory);
        ArgumentNullException.ThrowIfNull(cache);
        ArgumentNullException.ThrowIfNull(keyProvider);

        _next        = next;
        _options     = options.Value;
        _logger      = loggerFactory.CreateLogger <OutputCacheMiddleware>();
        _store       = cache;
        _keyProvider = keyProvider;
        _outputCacheEntryDispatcher = new();
        _requestDispatcher          = new();
    }
예제 #17
0
    public async Task ServesFreshContent_If_PathCasingDiffers(string method)
    {
        var options = new OutputCacheOptions {
            UseCaseSensitivePaths = true
        };
        var builders = TestUtils.CreateBuildersWithOutputCaching(options: options);

        foreach (var builder in builders)
        {
            using var host = builder.Build();

            await host.StartAsync();

            using var server = host.GetTestServer();
            var client          = server.CreateClient();
            var initialResponse = await client.SendAsync(TestUtils.CreateRequest(method, "path"));

            var subsequentResponse = await client.SendAsync(TestUtils.CreateRequest(method, "PATH"));

            await AssertFreshResponseAsync(initialResponse, subsequentResponse);
        }
    }
예제 #18
0
    public async Task ServesCachedContent_IfVaryQueryKeyStar_Matches_OrderInsensitive()
    {
        var options = new OutputCacheOptions();

        options.AddBasePolicy(b => b.VaryByQuery("*"));

        var builders = TestUtils.CreateBuildersWithOutputCaching(options: options);

        foreach (var builder in builders)
        {
            using var host = builder.Build();

            await host.StartAsync();

            using var server = host.GetTestServer();
            var client          = server.CreateClient();
            var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB");

            var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA");

            await AssertCachedResponseAsync(initialResponse, subsequentResponse);
        }
    }
예제 #19
0
 public string ReplaceDonutHoleContent(string content, ControllerContext filterContext, OutputCacheOptions options)
 {
     return(ReplaceDonutHoleContent(content, null, filterContext, options));
 }
예제 #20
0
        public string ReplaceDonutHoleContent(string content, ControllerContext filterContext, OutputCacheOptions options)
        {
            if (filterContext.IsChildAction &&
                (options & OutputCacheOptions.ReplaceDonutsInChildActions) != OutputCacheOptions.ReplaceDonutsInChildActions)
            {
                return(content);
            }

            return(DonutHoleRegex.Replace(content, match =>
            {
                var contentReference = JsonConvert.DeserializeObject <ContentReference>(match.Groups[1].Value);

                if (contentReference == null)
                {
                    return null;
                }

                var htmlToRenderWithoutDonutComment = new StringBuilder();

                using (var stringWriter = new StringWriter())
                {
                    var htmlHelper = EpiServerDonutHelper.CreateHtmlHelper(filterContext.Controller, stringWriter);

                    var repo = ServiceLocator.Current.GetInstance <IContentRepository>();
                    var epiContentToRender = repo.Get <IContent>(contentReference);

                    var openTag = OpenTagRegex.Match(match.Groups[1].ToString()).Groups[1].ToString();

                    if (!string.IsNullOrEmpty(openTag))
                    {
                        htmlToRenderWithoutDonutComment.Append(openTag);
                    }

                    EpiServerDonutHelper.RenderContentData(htmlHelper, epiContentToRender, string.Empty);
                    htmlToRenderWithoutDonutComment.Append(stringWriter.ToString());

                    var closeTag = CloseTagRegex.Match(match.Groups[1].ToString()).Groups[1].ToString();

                    if (!string.IsNullOrEmpty(closeTag))
                    {
                        htmlToRenderWithoutDonutComment.Append(closeTag);
                    }
                }

                return htmlToRenderWithoutDonutComment.ToString();
            }));
        }
예제 #21
0
        public string ReplaceDonutHoleContent(string content, string contentType, ControllerContext filterContext, OutputCacheOptions options)
        {
            if (
                filterContext.IsChildAction &&
                (options & OutputCacheOptions.ReplaceDonutsInChildActions) != OutputCacheOptions.ReplaceDonutsInChildActions)
            {
                return(content);
            }

            return(DonutHoles.Replace(content, match =>
            {
                var actionSettings = _actionSettingsSerialiser.Deserialise(match.Groups[1].Value);

                var actionResultString = InvokeAction(
                    filterContext.Controller,
                    actionSettings.ActionName,
                    actionSettings.ControllerName,
                    actionSettings.RouteValues
                    );

                // escape the string, so the parent's json is not broken
                // notice: rendering json objects with donut caching inside a json object is not supported!
                if (contentType != null && contentType.Equals("application/json", StringComparison.InvariantCultureIgnoreCase))
                {
                    var escaped = System.Web.Helpers.Json.Encode(actionResultString);

                    if (string.IsNullOrEmpty(escaped))
                    {
                        return escaped;
                    }

                    // the escaped string is wrapped in quotes
                    return escaped.Substring(1, escaped.Length - 2);
                }

                return actionResultString;
            }));
        }
 private static void AddOutputCaching(this IServiceCollection services, OutputCacheOptions options)
 {
     services.AddSingleton(options);
     services.TryAddSingleton <IOutputCachingService, OutputCachingService>();
     services.TryAddSingleton <IOutputCacheKeysProvider, OutputCacheKeysProvider>();
 }
예제 #23
0
 internal static IOutputCacheKeyProvider CreateTestKeyProvider(OutputCacheOptions options)
 {
     return(new OutputCacheKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options)));
 }