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) // Guid (long)
// Headers count // Headers count
// Header(s) (comma separated string) // Header(s) (comma separated string)
// Params count // QueryKey count
// Param(s) (comma separated string) // QueryKey(s) (comma separated string)
private static CachedVaryByRules ReadCachedVaryByRules(BinaryReader reader) private static CachedVaryByRules ReadCachedVaryByRules(BinaryReader reader)
{ {
var varyKeyPrefix = reader.ReadString(); var varyKeyPrefix = reader.ReadString();
@ -139,14 +139,14 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
{ {
headers[index] = reader.ReadString(); headers[index] = reader.ReadString();
} }
var paramCount = reader.ReadInt32(); var queryKeysCount = reader.ReadInt32();
var param = new string[paramCount]; var queryKeys = new string[queryKeysCount];
for (var index = 0; index < paramCount; index++) 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 // See serialization format above
@ -228,10 +228,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
writer.Write(header); writer.Write(header);
} }
writer.Write(varyByRules.Params.Count); writer.Write(varyByRules.QueryKeys.Count);
foreach (var param in varyByRules.Params) 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 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 HttpContext HttpContext { get; }
public bool ShouldCacheResponse { get; internal set; } public DateTimeOffset? ResponseTime { get; internal set; }
public string BaseKey { get; internal set; } public TimeSpan? CachedEntryAge { 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 CachedVaryByRules CachedVaryByRules { 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 bool ResponseStarted { get; set; }
internal Stream OriginalResponseStream { get; set; } internal Stream OriginalResponseStream { get; set; }

View File

@ -7,6 +7,6 @@ namespace Microsoft.AspNetCore.ResponseCaching
{ {
public class ResponseCacheFeature 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; var varyByRules = context.CachedVaryByRules;
if (varyByRules == null) if (varyByRules == null)
{ {
throw new InvalidOperationException($"{nameof(CachedVaryByRules)} must not be null on the {nameof(ResponseCacheContext)}"); 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; return varyByRules.VaryByKeyPrefix;
} }
@ -110,16 +110,16 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
} }
// Vary by query params // Vary by query keys
if (varyByRules?.Params.Count > 0) 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) builder.Append(KeyDelimiter)
.Append('Q'); .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)) foreach (var query in context.HttpContext.Request.Query.OrderBy(q => q.Key, StringComparer.OrdinalIgnoreCase))
{ {
builder.Append(KeyDelimiter) builder.Append(KeyDelimiter)
@ -130,13 +130,13 @@ namespace Microsoft.AspNetCore.ResponseCaching
} }
else else
{ {
foreach (var param in varyByRules.Params) foreach (var queryKey in varyByRules.QueryKeys)
{ {
builder.Append(KeyDelimiter) builder.Append(KeyDelimiter)
.Append(param) .Append(queryKey)
.Append("=") .Append("=")
// TODO: Perf - iterate the string values instead? // 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.CachedResponse = cachedResponse;
context.CachedResponseHeaders = new ResponseHeaders(cachedResponse.Headers); context.CachedResponseHeaders = new ResponseHeaders(cachedResponse.Headers);
context.ResponseTime = _options.SystemClock.UtcNow; 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; context.CachedEntryAge = cachedEntryAge > TimeSpan.Zero ? cachedEntryAge : TimeSpan.Zero;
if (_policyProvider.IsCachedEntryFresh(context)) if (_policyProvider.IsCachedEntryFresh(context))
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
response.Headers.Add(header); 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 ?? var body = context.CachedResponse.Body ??
((CachedResponseBody) await _store.GetAsync(context.CachedResponse.BodyKeyPrefix))?.Body; ((CachedResponseBody) await _store.GetAsync(context.CachedResponse.BodyKeyPrefix))?.Body;
@ -200,30 +200,30 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Create the cache entry now // Create the cache entry now
var response = context.HttpContext.Response; var response = context.HttpContext.Response;
var varyHeaderValue = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary)); var varyHeaders = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary));
var varyParamsValue = context.HttpContext.GetResponseCacheFeature()?.VaryByParams ?? StringValues.Empty; var varyQueryKeys = context.HttpContext.GetResponseCacheFeature()?.VaryByQueryKeys ?? StringValues.Empty;
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ?? context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
context.ResponseCacheControlHeaderValue.MaxAge ?? context.ResponseCacheControlHeaderValue.MaxAge ??
(context.ResponseExpires - context.ResponseTime) ?? (context.ResponseExpires - context.ResponseTime.Value) ??
DefaultExpirationTimeSpan; DefaultExpirationTimeSpan;
// Check if any vary rules exist // 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 // Normalize order and casing of vary by rules
var normalizedVaryHeaderValue = GetOrderCasingNormalizedStringValues(varyHeaderValue); var normalizedVaryHeaders = GetOrderCasingNormalizedStringValues(varyHeaders);
var normalizedVaryParamsValue = GetOrderCasingNormalizedStringValues(varyParamsValue); var normalizedVaryQueryKeys = GetOrderCasingNormalizedStringValues(varyQueryKeys);
// Update vary rules if they are different // Update vary rules if they are different
if (context.CachedVaryByRules == null || if (context.CachedVaryByRules == null ||
!StringValues.Equals(context.CachedVaryByRules.Params, normalizedVaryParamsValue) || !StringValues.Equals(context.CachedVaryByRules.QueryKeys, normalizedVaryQueryKeys) ||
!StringValues.Equals(context.CachedVaryByRules.Headers, normalizedVaryHeaderValue)) !StringValues.Equals(context.CachedVaryByRules.Headers, normalizedVaryHeaders))
{ {
context.CachedVaryByRules = new CachedVaryByRules context.CachedVaryByRules = new CachedVaryByRules
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = normalizedVaryHeaderValue, Headers = normalizedVaryHeaders,
Params = normalizedVaryParamsValue QueryKeys = normalizedVaryQueryKeys
}; };
} }
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Ensure date header is set // Ensure date header is set
if (!context.ResponseDate.HasValue) if (!context.ResponseDate.HasValue)
{ {
context.ResponseDate = context.ResponseTime; context.ResponseDate = context.ResponseTime.Value;
// Setting the date on the raw response headers. // Setting the date on the raw response headers.
context.TypedResponseHeaders.Date = context.ResponseDate; context.TypedResponseHeaders.Date = context.ResponseDate;
} }

View File

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

View File

@ -101,28 +101,28 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
} }
[Fact] [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() var cachedVaryByRule = new CachedVaryByRules()
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = param QueryKeys = queryKeys
}; };
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule))); AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
} }
[Fact] [Fact]
public void RoundTrip_CachedVaryByRule_HeadersAndParams_Succeeds() public void RoundTrip_CachedVaryByRule_HeadersAndQueryKeys_Succeeds()
{ {
var headers = new[] { "headerA", "headerB" }; var headers = new[] { "headerA", "headerB" };
var param = new[] { "paramA", "paramB" }; var queryKeys = new[] { "queryA", "queryB" };
var cachedVaryByRule = new CachedVaryByRules() var cachedVaryByRule = new CachedVaryByRules()
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = headers, Headers = headers,
Params = param QueryKeys = queryKeys
}; };
AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule))); AssertCachedVaryByRuleEqual(cachedVaryByRule, (CachedVaryByRules)CacheEntrySerializer.Deserialize(CacheEntrySerializer.Serialize(cachedVaryByRule)));
@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
Assert.NotNull(expected); Assert.NotNull(expected);
Assert.Equal(expected.VaryByKeyPrefix, actual.VaryByKeyPrefix); Assert.Equal(expected.VaryByKeyPrefix, actual.VaryByKeyPrefix);
Assert.Equal(expected.Headers, actual.Headers); 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] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedParamsOnly() public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedQueryKeysOnly()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); 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() context.CachedVaryByRules = new CachedVaryByRules()
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, 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)); cacheKeyProvider.CreateStorageVaryByKey(context));
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesParams_ParamNameCaseInsensitive_UseParamCasing() public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesQueryKeys_QueryKeyCaseInsensitive_UseQueryKeyCasing()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); 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() context.CachedVaryByRules = new CachedVaryByRules()
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, 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)); cacheKeyProvider.CreateStorageVaryByKey(context));
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesAllQueryParamsGivenAsterisk() public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesAllQueryKeysGivenAsterisk()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); 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() context.CachedVaryByRules = new CachedVaryByRules()
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Params = new string[] { "*" } QueryKeys = new string[] { "*" }
}; };
// To support case insensitivity, all param keys are converted to upper case. // To support case insensitivity, all query keys are converted to upper case.
// Explicit params uses the casing specified in the setting. // Explicit query keys uses the casing specified in the setting.
Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}PARAMA=ValueA{KeyDelimiter}PARAMB=ValueB", Assert.Equal($"{context.CachedVaryByRules.VaryByKeyPrefix}{KeyDelimiter}Q{KeyDelimiter}QUERYA=ValueA{KeyDelimiter}QUERYB=ValueB",
cacheKeyProvider.CreateStorageVaryByKey(context)); cacheKeyProvider.CreateStorageVaryByKey(context));
} }
[Fact] [Fact]
public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndParams() public void ResponseCacheKeyProvider_CreateStorageVaryKey_IncludesListedHeadersAndQueryKeys()
{ {
var cacheKeyProvider = TestUtils.CreateTestKeyProvider(); var cacheKeyProvider = TestUtils.CreateTestKeyProvider();
var context = TestUtils.CreateTestContext(); var context = TestUtils.CreateTestContext();
context.HttpContext.Request.Headers["HeaderA"] = "ValueA"; context.HttpContext.Request.Headers["HeaderA"] = "ValueA";
context.HttpContext.Request.Headers["HeaderB"] = "ValueB"; 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() context.CachedVaryByRules = new CachedVaryByRules()
{ {
VaryByKeyPrefix = FastGuid.NewGuid().IdString, VaryByKeyPrefix = FastGuid.NewGuid().IdString,
Headers = new string[] { "HeaderA", "HeaderC" }, 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)); cacheKeyProvider.CreateStorageVaryByKey(context));
} }
} }

View File

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

View File

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

View File

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

View File

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