API updates

- Internalize properties on ResponseCacheContext unless required by extension points
 - Rename VaryByParams -> VaryByQueryKeys
This commit is contained in:
John Luo 2016-09-20 14:29:42 -07:00
parent 6891d00032
commit 5e12a103a4
13 changed files with 120 additions and 116 deletions

View File

@ -127,8 +127,8 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
// Guid (long)
// Headers count
// Header(s) (comma separated string)
// Params count
// Param(s) (comma separated string)
// QueryKey count
// QueryKey(s) (comma separated string)
private static CachedVaryByRules ReadCachedVaryByRules(BinaryReader reader)
{
var varyKeyPrefix = reader.ReadString();
@ -139,14 +139,14 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
{
headers[index] = reader.ReadString();
}
var paramCount = reader.ReadInt32();
var param = new string[paramCount];
for (var index = 0; index < paramCount; index++)
var queryKeysCount = reader.ReadInt32();
var queryKeys = new string[queryKeysCount];
for (var index = 0; index < queryKeysCount; index++)
{
param[index] = reader.ReadString();
queryKeys[index] = reader.ReadString();
}
return new CachedVaryByRules { VaryByKeyPrefix = varyKeyPrefix, Headers = headers, Params = param };
return new CachedVaryByRules { VaryByKeyPrefix = varyKeyPrefix, Headers = headers, QueryKeys = queryKeys };
}
// See serialization format above
@ -228,10 +228,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
writer.Write(header);
}
writer.Write(varyByRules.Params.Count);
foreach (var param in varyByRules.Params)
writer.Write(varyByRules.QueryKeys.Count);
foreach (var queryKey in varyByRules.QueryKeys)
{
writer.Write(param);
writer.Write(queryKey);
}
}
}

View File

@ -11,6 +11,6 @@ namespace Microsoft.AspNetCore.ResponseCaching
public StringValues Headers { get; set; }
public StringValues Params { get; set; }
public StringValues QueryKeys { get; set; }
}
}

View File

@ -32,22 +32,22 @@ namespace Microsoft.AspNetCore.ResponseCaching
public HttpContext HttpContext { get; }
public bool ShouldCacheResponse { get; internal set; }
public DateTimeOffset? ResponseTime { get; internal set; }
public string BaseKey { get; internal set; }
public string StorageVaryKey { get; internal set; }
public DateTimeOffset ResponseTime { get; internal set; }
public TimeSpan CachedEntryAge { get; internal set; }
public TimeSpan CachedResponseValidFor { get; internal set; }
public CachedResponse CachedResponse { get; internal set; }
public TimeSpan? CachedEntryAge { get; internal set; }
public CachedVaryByRules CachedVaryByRules { get; internal set; }
internal bool ShouldCacheResponse { get; set; }
internal string BaseKey { get; set; }
internal string StorageVaryKey { get; set; }
internal TimeSpan CachedResponseValidFor { get; set; }
internal CachedResponse CachedResponse { get; set; }
internal bool ResponseStarted { get; set; }
internal Stream OriginalResponseStream { get; set; }

View File

@ -7,6 +7,6 @@ namespace Microsoft.AspNetCore.ResponseCaching
{
public class ResponseCacheFeature
{
public StringValues VaryByParams { get; set; }
public StringValues VaryByQueryKeys { get; set; }
}
}

View File

@ -75,12 +75,12 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
var varyByRules = context.CachedVaryByRules;
if (varyByRules == null)
if (varyByRules == null)
{
throw new InvalidOperationException($"{nameof(CachedVaryByRules)} must not be null on the {nameof(ResponseCacheContext)}");
}
if ((StringValues.IsNullOrEmpty(varyByRules.Headers) && StringValues.IsNullOrEmpty(varyByRules.Params)))
if ((StringValues.IsNullOrEmpty(varyByRules.Headers) && StringValues.IsNullOrEmpty(varyByRules.QueryKeys)))
{
return varyByRules.VaryByKeyPrefix;
}
@ -110,16 +110,16 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
}
// Vary by query params
if (varyByRules?.Params.Count > 0)
// Vary by query keys
if (varyByRules?.QueryKeys.Count > 0)
{
// Append a group separator for the query parameter segment of the cache key
// Append a group separator for the query key segment of the cache key
builder.Append(KeyDelimiter)
.Append('Q');
if (varyByRules.Params.Count == 1 && string.Equals(varyByRules.Params[0], "*", StringComparison.Ordinal))
if (varyByRules.QueryKeys.Count == 1 && string.Equals(varyByRules.QueryKeys[0], "*", StringComparison.Ordinal))
{
// Vary by all available query params
// Vary by all available query keys
foreach (var query in context.HttpContext.Request.Query.OrderBy(q => q.Key, StringComparer.OrdinalIgnoreCase))
{
builder.Append(KeyDelimiter)
@ -130,13 +130,13 @@ namespace Microsoft.AspNetCore.ResponseCaching
}
else
{
foreach (var param in varyByRules.Params)
foreach (var queryKey in varyByRules.QueryKeys)
{
builder.Append(KeyDelimiter)
.Append(param)
.Append(queryKey)
.Append("=")
// TODO: Perf - iterate the string values instead?
.Append(context.HttpContext.Request.Query[param]);
.Append(context.HttpContext.Request.Query[queryKey]);
}
}
}

View File

@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
context.CachedResponse = cachedResponse;
context.CachedResponseHeaders = new ResponseHeaders(cachedResponse.Headers);
context.ResponseTime = _options.SystemClock.UtcNow;
var cachedEntryAge = context.ResponseTime - context.CachedResponse.Created;
var cachedEntryAge = context.ResponseTime.Value - context.CachedResponse.Created;
context.CachedEntryAge = cachedEntryAge > TimeSpan.Zero ? cachedEntryAge : TimeSpan.Zero;
if (_policyProvider.IsCachedEntryFresh(context))
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
response.Headers.Add(header);
}
response.Headers[HeaderNames.Age] = context.CachedEntryAge.TotalSeconds.ToString("F0", CultureInfo.InvariantCulture);
response.Headers[HeaderNames.Age] = context.CachedEntryAge.Value.TotalSeconds.ToString("F0", CultureInfo.InvariantCulture);
var body = context.CachedResponse.Body ??
((CachedResponseBody) await _store.GetAsync(context.CachedResponse.BodyKeyPrefix))?.Body;
@ -200,30 +200,30 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Create the cache entry now
var response = context.HttpContext.Response;
var varyHeaderValue = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary));
var varyParamsValue = context.HttpContext.GetResponseCacheFeature()?.VaryByParams ?? StringValues.Empty;
var varyHeaders = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary));
var varyQueryKeys = context.HttpContext.GetResponseCacheFeature()?.VaryByQueryKeys ?? StringValues.Empty;
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
context.ResponseCacheControlHeaderValue.MaxAge ??
(context.ResponseExpires - context.ResponseTime) ??
(context.ResponseExpires - context.ResponseTime.Value) ??
DefaultExpirationTimeSpan;
// Check if any vary rules exist
if (!StringValues.IsNullOrEmpty(varyHeaderValue) || !StringValues.IsNullOrEmpty(varyParamsValue))
if (!StringValues.IsNullOrEmpty(varyHeaders) || !StringValues.IsNullOrEmpty(varyQueryKeys))
{
// Normalize order and casing of vary by rules
var normalizedVaryHeaderValue = GetOrderCasingNormalizedStringValues(varyHeaderValue);
var normalizedVaryParamsValue = GetOrderCasingNormalizedStringValues(varyParamsValue);
var normalizedVaryHeaders = GetOrderCasingNormalizedStringValues(varyHeaders);
var normalizedVaryQueryKeys = GetOrderCasingNormalizedStringValues(varyQueryKeys);
// Update vary rules if they are different
if (context.CachedVaryByRules == null ||
!StringValues.Equals(context.CachedVaryByRules.Params, normalizedVaryParamsValue) ||
!StringValues.Equals(context.CachedVaryByRules.Headers, normalizedVaryHeaderValue))
!StringValues.Equals(context.CachedVaryByRules.QueryKeys, normalizedVaryQueryKeys) ||
!StringValues.Equals(context.CachedVaryByRules.Headers, normalizedVaryHeaders))
{
context.CachedVaryByRules = new CachedVaryByRules
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = normalizedVaryHeaderValue,
Params = normalizedVaryParamsValue
Headers = normalizedVaryHeaders,
QueryKeys = normalizedVaryQueryKeys
};
}
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Ensure date header is set
if (!context.ResponseDate.HasValue)
{
context.ResponseDate = context.ResponseTime;
context.ResponseDate = context.ResponseTime.Value;
// Setting the date on the raw response headers.
context.TypedResponseHeaders.Date = context.ResponseDate;
}

View File

@ -104,14 +104,14 @@ namespace Microsoft.AspNetCore.ResponseCaching
{
if (!context.ResponseCacheControlHeaderValue.SharedMaxAge.HasValue &&
!context.ResponseCacheControlHeaderValue.MaxAge.HasValue &&
context.ResponseTime >= context.ResponseExpires)
context.ResponseTime.Value >= context.ResponseExpires)
{
return false;
}
}
else
{
var age = context.ResponseTime - context.ResponseDate.Value;
var age = context.ResponseTime.Value - context.ResponseDate.Value;
// Validate shared max age
if (age >= context.ResponseCacheControlHeaderValue.SharedMaxAge)
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
else if (!context.ResponseCacheControlHeaderValue.MaxAge.HasValue)
{
// Validate expiration
if (context.ResponseTime >= context.ResponseExpires)
if (context.ResponseTime.Value >= context.ResponseExpires)
{
return false;
}
@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
public virtual bool IsCachedEntryFresh(ResponseCacheContext context)
{
var age = context.CachedEntryAge;
var age = context.CachedEntryAge.Value;
var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl;
// Add min-fresh requirements
@ -178,7 +178,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
else if (!cachedControlHeaders.MaxAge.HasValue && !context.RequestCacheControlHeaderValue.MaxAge.HasValue)
{
// Validate expiration
if (context.ResponseTime >= context.CachedResponseHeaders.Expires)
if (context.ResponseTime.Value >= context.CachedResponseHeaders.Expires)
{
return false;
}

View File

@ -101,28 +101,28 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
[Fact]
public void RoundTrip_CachedVaryByRule_ParamsOnly_Succeeds()
public void RoundTrip_CachedVaryByRule_QueryKeysOnly_Succeeds()
{
var param = new[] { "paramA", "paramB" };
var queryKeys = new[] { "queryA", "queryB" };
var cachedVaryByRule = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = param
QueryKeys = queryKeys
};
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
}
[Fact]
public void RoundTrip_CachedVaryByRule_HeadersAndParams_Succeeds()
public void RoundTrip_CachedVaryByRule_HeadersAndQueryKeys_Succeeds()
{
var headers = new[] { "headerA", "headerB" };
var param = new[] { "paramA", "paramB" };
var queryKeys = new[] { "queryA", "queryB" };
var cachedVaryByRule = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = headers,
Params = param
QueryKeys = queryKeys
};
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Assert.NotNull(expected);
Assert.Equal(expected.VaryByKeyPrefix, actual.VaryByKeyPrefix);
Assert.Equal(expected.Headers, actual.Headers);
Assert.Equal(expected.Params, actual.Params);
Assert.Equal(expected.QueryKeys, actual.QueryKeys);
}
}
}

View File

@ -95,71 +95,71 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
[Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedParamsOnly()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedQueryKeysOnly()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.QueryString = new QueryString("?ParamA=ValueA&ParamB=ValueB");
context.HttpContext.Request.QueryString = new QueryString("?QueryA=ValueA&QueryB=ValueB");
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "ParamA", "ParamC" }
QueryKeys = new string[] { "QueryA", "QueryC" }
};
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}QueryA=ValueA{KeyDelimiter}QueryC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesParams_ParamNameCaseInsensitive_UseParamCasing()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesQueryKeys_QueryKeyCaseInsensitive_UseQueryKeyCasing()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.QueryString = new QueryString("?parama=ValueA&paramB=ValueB");
context.HttpContext.Request.QueryString = new QueryString("?queryA=ValueA&queryB=ValueB");
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "ParamA", "ParamC" }
QueryKeys = new string[] { "QueryA", "QueryC" }
};
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}QueryA=ValueA{KeyDelimiter}QueryC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesAllQueryParamsGivenAsterisk()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesAllQueryKeysGivenAsterisk()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.QueryString = new QueryString("?ParamA=ValueA&ParamB=ValueB");
context.HttpContext.Request.QueryString = new QueryString("?QueryA=ValueA&QueryB=ValueB");
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "*" }
QueryKeys = new string[] { "*" }
};
// To support case insensitivity, all param keys are converted to upper case.
// Explicit params uses the casing specified in the setting.
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}PARAMA=ValueA{KeyDelimiter}PARAMB=ValueB",
// To support case insensitivity, all query keys are converted to upper case.
// Explicit query keys uses the casing specified in the setting.
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}QUERYA=ValueA{KeyDelimiter}QUERYB=ValueB",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
[Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndParams()
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndQueryKeys()
{
var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Headers["HeaderA"] = "ValueA";
context.HttpContext.Request.Headers["HeaderB"] = "ValueB";
context.HttpContext.Request.QueryString = new QueryString("?ParamA=ValueA&ParamB=ValueB");
context.HttpContext.Request.QueryString = new QueryString("?QueryA=ValueA&QueryB=ValueB");
context.CachedVaryByRules = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = new string[] { "HeaderA", "HeaderC" },
Params = new string[] { "ParamA", "ParamC" }
QueryKeys = new string[] { "QueryA", "QueryC" }
};
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}H{KeyDelimiter}HeaderA=ValueA{KeyDelimiter}HeaderC={KeyDelimiter}Q{KeyDelimiter}ParamA=ValueA{KeyDelimiter}ParamC=",
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}H{KeyDelimiter}HeaderA=ValueA{KeyDelimiter}HeaderC={KeyDelimiter}Q{KeyDelimiter}QueryA=ValueA{KeyDelimiter}QueryC=",
cacheKeyProvider.CreateStorageVaryByKey(context));
}
}

View File

@ -292,7 +292,6 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
MaxAge = TimeSpan.FromSeconds(12)
};
context.ResponseTime = DateTimeOffset.UtcNow;
context.TypedResponseHeaders.Expires = context.ResponseTime + TimeSpan.FromSeconds(11);
await middleware.FinalizeCacheHeadersAsync(context);
@ -311,7 +310,6 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
SharedMaxAge = TimeSpan.FromSeconds(13)
};
context.ResponseTime = DateTimeOffset.UtcNow;
context.TypedResponseHeaders.Expires = context.ResponseTime + TimeSpan.FromSeconds(11);
await middleware.FinalizeCacheHeadersAsync(context);
@ -328,11 +326,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB", "HEADERc" });
context.HttpContext.AddResponseCacheFeature();
context.HttpContext.GetResponseCacheFeature().VaryByParams = new StringValues(new[] { "paramB", "PARAMAA" });
context.HttpContext.GetResponseCacheFeature().VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" });
var cachedVaryByRules = new CachedVaryByRules()
{
Headers = new StringValues(new[] { "HeaderA", "HeaderB" }),
Params = new StringValues(new[] { "ParamA", "ParamB" })
QueryKeys = new StringValues(new[] { "QueryA", "QueryB" })
};
context.CachedVaryByRules = cachedVaryByRules;
@ -352,12 +350,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB" });
context.HttpContext.AddResponseCacheFeature();
context.HttpContext.GetResponseCacheFeature().VaryByParams = new StringValues(new[] { "paramB", "PARAMA" });
context.HttpContext.GetResponseCacheFeature().VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" });
var cachedVaryByRules = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = new StringValues(new[] { "HEADERA", "HEADERB" }),
Params = new StringValues(new[] { "PARAMA", "PARAMB" })
QueryKeys = new StringValues(new[] { "QUERYA", "QUERYB" })
};
context.CachedVaryByRules = cachedVaryByRules;

View File

@ -385,6 +385,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
context.ResponseTime = DateTimeOffset.MaxValue;
context.CachedEntryAge = TimeSpan.MaxValue;
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary());
Assert.True(new ResponseCachePolicyProvider().IsCachedEntryFresh(context));
@ -396,6 +397,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
context.ResponseTime = DateTimeOffset.MaxValue;
context.CachedEntryAge = TimeSpan.MaxValue;
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
{
CacheControl = new CacheControlHeaderValue()
@ -413,6 +415,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var utcNow = DateTimeOffset.UtcNow;
var context = TestUtils.CreateTestContext();
context.ResponseTime = utcNow;
context.CachedEntryAge = TimeSpan.Zero;
context.CachedResponseHeaders = new ResponseHeaders(new HeaderDictionary())
{
CacheControl = new CacheControlHeaderValue()

View File

@ -88,152 +88,152 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
}
[Fact]
public async void ServesCachedContent_IfVaryParams_Matches()
public async void ServesCachedContent_IfVaryQueryKeys_Matches()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = "param";
context.GetResponseCacheFeature().VaryByQueryKeys = "query";
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?param=value");
var subsequentResponse = await client.GetAsync("?param=value");
var initialResponse = await client.GetAsync("?query=value");
var subsequentResponse = await client.GetAsync("?query=value");
await AssertResponseCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesCachedContent_IfVaryParamsExplicit_Matches_ParamNameCaseInsensitive()
public async void ServesCachedContent_IfVaryQueryKeysExplicit_Matches_QueryKeyCaseInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = new[] { "ParamA", "paramb" };
context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "QueryA", "queryb" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?parama=valuea&paramb=valueb");
var subsequentResponse = await client.GetAsync("?ParamA=valuea&ParamB=valueb");
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?QueryA=valuea&QueryB=valueb");
await AssertResponseCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesCachedContent_IfVaryParamsStar_Matches_ParamNameCaseInsensitive()
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_QueryKeyCaseInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = new[] { "*" };
context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?parama=valuea&paramb=valueb");
var subsequentResponse = await client.GetAsync("?ParamA=valuea&ParamB=valueb");
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?QueryA=valuea&QueryB=valueb");
await AssertResponseCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesCachedContent_IfVaryParamsExplicit_Matches_OrderInsensitive()
public async void ServesCachedContent_IfVaryQueryKeyExplicit_Matches_OrderInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = new[] { "ParamB", "ParamA" };
context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "QueryB", "QueryA" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?ParamA=ValueA&ParamB=ValueB");
var subsequentResponse = await client.GetAsync("?ParamB=ValueB&ParamA=ValueA");
var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB");
var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA");
await AssertResponseCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesCachedContent_IfVaryParamsStar_Matches_OrderInsensitive()
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_OrderInsensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = new[] { "*" };
context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?ParamA=ValueA&ParamB=ValueB");
var subsequentResponse = await client.GetAsync("?ParamB=ValueB&ParamA=ValueA");
var initialResponse = await client.GetAsync("?QueryA=ValueA&QueryB=ValueB");
var subsequentResponse = await client.GetAsync("?QueryB=ValueB&QueryA=ValueA");
await AssertResponseCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesFreshContent_IfVaryParams_Mismatches()
public async void ServesFreshContent_IfVaryQueryKey_Mismatches()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = "param";
context.GetResponseCacheFeature().VaryByQueryKeys = "query";
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?param=value");
var subsequentResponse = await client.GetAsync("?param=value2");
var initialResponse = await client.GetAsync("?query=value");
var subsequentResponse = await client.GetAsync("?query=value2");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesFreshContent_IfVaryParamsExplicit_Mismatch_ParamValueCaseSensitive()
public async void ServesFreshContent_IfVaryQueryKeyExplicit_Mismatch_QueryKeyCaseSensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = new[] { "ParamA", "ParamB" };
context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "QueryA", "QueryB" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?parama=valuea&paramb=valueb");
var subsequentResponse = await client.GetAsync("?parama=ValueA&paramb=ValueB");
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?querya=ValueA&queryb=ValueB");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse);
}
}
[Fact]
public async void ServesFreshContent_IfVaryParamsStar_Mismatch_ParamValueCaseSensitive()
public async void ServesFreshContent_IfVaryQueryKeyStar_Mismatch_QueryKeyValueCaseSensitive()
{
var builder = TestUtils.CreateBuilderWithResponseCache(requestDelegate: async (context) =>
{
context.GetResponseCacheFeature().VaryByParams = new[] { "*" };
context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var initialResponse = await client.GetAsync("?parama=valuea&paramb=valueb");
var subsequentResponse = await client.GetAsync("?parama=ValueA&paramb=ValueB");
var initialResponse = await client.GetAsync("?querya=valuea&queryb=valueb");
var subsequentResponse = await client.GetAsync("?querya=ValueA&queryb=ValueB");
await AssertResponseNotCachedAsync(initialResponse, subsequentResponse);
}

View File

@ -108,7 +108,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
internal static ResponseCacheContext CreateTestContext()
{
return new ResponseCacheContext(new DefaultHttpContext());
return new ResponseCacheContext(new DefaultHttpContext())
{
ResponseTime = DateTimeOffset.UtcNow
};
}
}