public void BuildPolicy_CreatesDefaultPolicy()
    {
        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.Build();

        Assert.Equal(DefaultPolicy.Instance, policy);
    }
Пример #2
0
    /// <summary>
    /// Builds and adds an <see cref="IOutputCachePolicy"/> instance to base policies.
    /// </summary>
    /// <param name="build">an action on <see cref="OutputCachePolicyBuilder"/>.</param>
    public void AddBasePolicy(Action <OutputCachePolicyBuilder> build)
    {
        var builder = new OutputCachePolicyBuilder();

        build(builder);
        BasePolicies ??= new();
        BasePolicies.Add(builder.Build());
    }
Пример #3
0
    /// <summary>
    /// Defines a <see cref="IOutputCachePolicy"/> which can be referenced by name.
    /// </summary>
    /// <param name="name">The name of the policy.</param>
    /// <param name="build">an action on <see cref="OutputCachePolicyBuilder"/>.</param>
    public void AddPolicy(string name, Action <OutputCachePolicyBuilder> build)
    {
        var builder = new OutputCachePolicyBuilder();

        build(builder);
        NamedPolicies ??= new Dictionary <string, IOutputCachePolicy>(StringComparer.OrdinalIgnoreCase);
        NamedPolicies[name] = builder.Build();
    }
    public async Task BuildPolicy_CreatesNoStorePolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

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

        Assert.False(context.EnableOutputCaching);
    }
    public async Task BuildPolicy_DisablesLocking()
    {
        var context = TestUtils.CreateUninitializedContext();

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.AllowLocking(false).Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.False(context.AllowLocking);
    }
    public async Task BuildPolicy_CreatesVaryByValuePolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.VaryByValue(context => new KeyValuePair <string, string>("color", "blue")).Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Equal("blue", context.CacheVaryByRules.VaryByCustom["color"]);
    }
    public async Task IsResponseCacheable_NoPublic_IsAllowed()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.ServeResponseAsync(context, default);

        Assert.True(context.AllowCacheStorage);
        Assert.True(context.AllowCacheLookup);
        Assert.Empty(sink.Writes);
    }
    public async Task BuildPolicy_CreatesExpirePolicy()
    {
        var context  = TestUtils.CreateUninitializedContext();
        var duration = 42;

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.Expire(TimeSpan.FromSeconds(duration)).Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Equal(duration, context.ResponseExpirationTimeSpan?.TotalSeconds);
    }
    public async Task BuildPolicy_CreatesTagPolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.Tag("tag1", "tag2").Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Contains("tag1", context.Tags);
        Assert.Contains("tag2", context.Tags);
    }
    public async Task IsResponseCacheable_NonSuccessStatusCodes_NotAllowed(int statusCode)
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Response.StatusCode = statusCode;

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.ServeResponseAsync(context, default);

        Assert.True(context.AllowCacheLookup);
        Assert.False(context.AllowCacheStorage);
    }
    public async Task AttemptOutputCaching_UncacheableMethods_NotAllowed(string method)
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);
        var policy  = new OutputCachePolicyBuilder().Build();

        context.HttpContext.Request.Method = method;

        await policy.CacheRequestAsync(context, default);

        Assert.False(context.AllowCacheLookup);
        Assert.False(context.AllowCacheStorage);
    }
    public async Task BuildPolicy_ClearsDefaultPolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

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

        Assert.False(context.AllowLocking);
        Assert.False(context.AllowCacheLookup);
        Assert.False(context.AllowCacheStorage);
        Assert.False(context.EnableOutputCaching);
    }
    public async Task IsResponseCacheable_SetCookieHeader_NotAllowed()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Response.Headers.SetCookie = "cookieName=cookieValue";

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.ServeResponseAsync(context, default);

        Assert.False(context.AllowCacheStorage);
        Assert.True(context.AllowCacheLookup);
    }
    public async Task AllowCacheLookup_LegacyDirectives_OverridenByCacheControl()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Request.Method               = HttpMethods.Get;
        context.HttpContext.Request.Headers.Pragma       = "no-cache";
        context.HttpContext.Request.Headers.CacheControl = "max-age=10";

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.CacheRequestAsync(context, default);

        Assert.True(context.AllowCacheLookup);
        Assert.Empty(sink.Writes);
    }
    public async Task BuildPolicy_CreatesVaryByQueryPolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

        context.HttpContext.Request.QueryString = new QueryString("?QueryA=ValueA&QueryB=ValueB");

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.VaryByQuery("QueryA", "QueryC").Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Contains("QueryA", (IEnumerable <string>)context.CacheVaryByRules.QueryKeys);
        Assert.Contains("QueryC", (IEnumerable <string>)context.CacheVaryByRules.QueryKeys);
        Assert.DoesNotContain("QueryB", (IEnumerable <string>)context.CacheVaryByRules.QueryKeys);
    }
    /// <summary>
    /// Marks an endpoint to be cached using the specified policy builder.
    /// </summary>
    public static TBuilder CacheOutput <TBuilder>(this TBuilder builder, Action <OutputCachePolicyBuilder> policy) where TBuilder : IEndpointConventionBuilder
    {
        ArgumentNullException.ThrowIfNull(builder);

        var outputCachePolicyBuilder = new OutputCachePolicyBuilder();

        policy?.Invoke(outputCachePolicyBuilder);

        builder.Add(endpointBuilder =>
        {
            endpointBuilder.Metadata.Add(outputCachePolicyBuilder.Build());
        });

        return(builder);
    }
    public async Task AttemptResponseCaching_AuthorizationHeaders_NotAllowed()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Request.Method = HttpMethods.Get;
        context.HttpContext.Request.Headers.Authorization = "Placeholder";

        var policy = new OutputCachePolicyBuilder().Build();

        await policy.CacheRequestAsync(context, default);

        Assert.False(context.AllowCacheStorage);
        Assert.False(context.AllowCacheLookup);
    }
    public async Task BuildPolicy_CreatesVaryByHeaderPolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

        context.HttpContext.Request.Headers["HeaderA"] = "ValueA";
        context.HttpContext.Request.Headers["HeaderB"] = "ValueB";

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.VaryByHeader("HeaderA", "HeaderC").Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Contains("HeaderA", (IEnumerable <string>)context.CacheVaryByRules.HeaderNames);
        Assert.Contains("HeaderC", (IEnumerable <string>)context.CacheVaryByRules.HeaderNames);
        Assert.DoesNotContain("HeaderB", (IEnumerable <string>)context.CacheVaryByRules.HeaderNames);
    }
    public async Task AllowCacheStorage_NoStore_IsAllowed()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Request.Method = HttpMethods.Get;
        context.HttpContext.Request.Headers.CacheControl = new CacheControlHeaderValue()
        {
            NoStore = true
        }.ToString();

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.CacheRequestAsync(context, default);

        Assert.True(context.AllowCacheStorage);
        Assert.Empty(sink.Writes);
    }
    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 IsResponseCacheable_Private_IsAllowed()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
        {
            Private = true
        }.ToString();

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.ServeResponseAsync(context, default);

        Assert.True(context.AllowCacheStorage);
        Assert.True(context.AllowCacheLookup);
        Assert.Empty(sink.Writes);
    }
    public async Task BuildPolicy_CreatesVaryByRoutePolicy()
    {
        var context = TestUtils.CreateUninitializedContext();

        context.HttpContext.Request.RouteValues = new Routing.RouteValueDictionary()
        {
            ["RouteA"] = "ValueA",
            ["RouteB"] = 123.456,
        };

        var builder = new OutputCachePolicyBuilder();
        var policy  = builder.VaryByRouteValue("RouteA", "RouteC").Build();
        await policy.CacheRequestAsync(context, cancellation : default);

        Assert.True(context.EnableOutputCaching);
        Assert.Contains("RouteA", (IEnumerable <string>)context.CacheVaryByRules.RouteValueNames);
        Assert.Contains("RouteC", (IEnumerable <string>)context.CacheVaryByRules.RouteValueNames);
        Assert.DoesNotContain("RouteB", (IEnumerable <string>)context.CacheVaryByRules.RouteValueNames);
    }
    public async Task IsResponseCacheable_NoExpiryRequirements_IsAllowed()
    {
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;

        var utcNow = DateTimeOffset.UtcNow;

        context.HttpContext.Response.Headers.Date = HeaderUtilities.FormatDate(utcNow);
        context.ResponseTime = DateTimeOffset.MaxValue;

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.ServeResponseAsync(context, default);

        Assert.True(context.AllowCacheStorage);
        Assert.True(context.AllowCacheLookup);
        Assert.Empty(sink.Writes);
    }
    public async Task IsResponseCacheable_SharedMaxAgeOverridesMaxAge_IsAllowed()
    {
        var utcNow  = DateTimeOffset.UtcNow;
        var sink    = new TestSink();
        var context = TestUtils.CreateTestContext(testSink: sink);

        context.HttpContext.Response.StatusCode           = StatusCodes.Status200OK;
        context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
        {
            MaxAge       = TimeSpan.FromSeconds(10),
            SharedMaxAge = TimeSpan.FromSeconds(15)
        }.ToString();
        context.HttpContext.Response.Headers.Date = HeaderUtilities.FormatDate(utcNow);
        context.ResponseTime = utcNow + TimeSpan.FromSeconds(11);

        var policy = new OutputCachePolicyBuilder().Build();
        await policy.ServeResponseAsync(context, default);

        Assert.True(context.AllowCacheStorage);
        Assert.True(context.AllowCacheLookup);
        Assert.Empty(sink.Writes);
    }