diff --git a/src/Microsoft.AspNetCore.Mvc.Core/CacheProfile.cs b/src/Microsoft.AspNetCore.Mvc.Core/CacheProfile.cs
index 92422c2ac5..15998b31ea 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/CacheProfile.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/CacheProfile.cs
@@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc
///
/// Gets or sets the duration in seconds for which the response is cached.
/// If this property is set to a non null value,
- /// the "max-age" in "Cache-control" header is set in the
+ /// the "max-age" in "Cache-control" header is set in the
/// .
///
public int? Duration { get; set; }
@@ -36,5 +36,13 @@ namespace Microsoft.AspNetCore.Mvc
/// Gets or sets the value for the Vary header in .
///
public string VaryByHeader { get; set; }
+
+ ///
+ /// Gets or sets the query keys to vary by.
+ ///
+ ///
+ /// requires the response cache middleware.
+ ///
+ public string[] VaryByQueryKeys { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ResponseCacheFilter.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ResponseCacheFilter.cs
index b27ec02e93..6577ad36e5 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ResponseCacheFilter.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ResponseCacheFilter.cs
@@ -7,6 +7,7 @@ using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.ResponseCaching;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Mvc.Internal
@@ -21,6 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private ResponseCacheLocation? _cacheLocation;
private bool? _cacheNoStore;
private string _cacheVaryByHeader;
+ private string[] _cacheVaryByQueryKeys;
///
/// Creates a new instance of
@@ -73,6 +75,18 @@ namespace Microsoft.AspNetCore.Mvc.Internal
set { _cacheVaryByHeader = value; }
}
+ ///
+ /// Gets or sets the query keys to vary by.
+ ///
+ ///
+ /// requires the response cache middleware.
+ ///
+ public string[] VaryByQueryKeys
+ {
+ get { return _cacheVaryByQueryKeys ?? _cacheProfile.VaryByQueryKeys; }
+ set { _cacheVaryByQueryKeys = value; }
+ }
+
///
public void OnActionExecuting(ActionExecutingContext context)
{
@@ -110,6 +124,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal
headers[HeaderNames.Vary] = VaryByHeader;
}
+ if (VaryByQueryKeys != null)
+ {
+ var responseCachingFeature = context.HttpContext.Features.Get();
+ if (responseCachingFeature == null)
+ {
+ throw new InvalidOperationException(Resources.FormatVaryByQueryKeys_Requires_ResponseCachingMiddleware(nameof(VaryByQueryKeys)));
+ }
+ responseCachingFeature.VaryByQueryKeys = VaryByQueryKeys;
+ }
+
if (NoStore)
{
headers[HeaderNames.CacheControl] = "no-store";
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
index 6964666fbb..ab08d318b2 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
@@ -1338,6 +1338,22 @@ namespace Microsoft.AspNetCore.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("FormCollectionModelBinder_CannotBindToFormCollection"), p0, p1, p2);
}
+ ///
+ /// VaryByQueryKeys requires the response cache middleware.
+ ///
+ internal static string VaryByQueryKeys_Requires_ResponseCachingMiddleware
+ {
+ get { return GetString("VaryByQueryKeys_Requires_ResponseCachingMiddleware"); }
+ }
+
+ ///
+ /// VaryByQueryKeys requires the response cache middleware.
+ ///
+ internal static string FormatVaryByQueryKeys_Requires_ResponseCachingMiddleware(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("VaryByQueryKeys_Requires_ResponseCachingMiddleware"), p0);
+ }
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
index a054806f71..e5d07f4d0f 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
@@ -376,4 +376,7 @@
The '{0}' cannot bind to a model of type '{1}'. Change the model type to '{2}' instead.
+
+ '{0}' requires the response cache middleware.
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ResponseCacheAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Core/ResponseCacheAttribute.cs
index 9bddb6a66b..553be45b09 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ResponseCacheAttribute.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ResponseCacheAttribute.cs
@@ -77,6 +77,14 @@ namespace Microsoft.AspNetCore.Mvc
///
public string VaryByHeader { get; set; }
+ ///
+ /// Gets or sets the query keys to vary by.
+ ///
+ ///
+ /// requires the response cache middleware.
+ ///
+ public string[] VaryByQueryKeys { get; set; }
+
///
/// Gets or sets the value of the cache profile name.
///
@@ -117,6 +125,7 @@ namespace Microsoft.AspNetCore.Mvc
_noStore = _noStore ?? selectedProfile?.NoStore;
_location = _location ?? selectedProfile?.Location;
VaryByHeader = VaryByHeader ?? selectedProfile?.VaryByHeader;
+ VaryByQueryKeys = VaryByQueryKeys ?? selectedProfile?.VaryByQueryKeys;
// ResponseCacheFilter cannot take any null values. Hence, if there are any null values,
// the properties convert them to their defaults and are passed on.
@@ -125,7 +134,8 @@ namespace Microsoft.AspNetCore.Mvc
Duration = _duration,
Location = _location,
NoStore = _noStore,
- VaryByHeader = VaryByHeader
+ VaryByHeader = VaryByHeader,
+ VaryByQueryKeys = VaryByQueryKeys,
});
}
}
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/project.json b/src/Microsoft.AspNetCore.Mvc.Core/project.json
index 64203d282e..3f463ec966 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/project.json
+++ b/src/Microsoft.AspNetCore.Mvc.Core/project.json
@@ -24,6 +24,7 @@
"Microsoft.AspNetCore.Hosting.Abstractions": "1.1.0-*",
"Microsoft.AspNetCore.Http": "1.1.0-*",
"Microsoft.AspNetCore.Mvc.Abstractions": "1.1.0-*",
+ "Microsoft.AspNetCore.ResponseCaching.Abstractions": "1.0.0-*",
"Microsoft.AspNetCore.Routing": "1.1.0-*",
"Microsoft.AspNetCore.Routing.DecisionTree.Sources": {
"type": "build",
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ResponseCacheFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ResponseCacheFilterTest.cs
index 4e8248266d..c04b67adec 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ResponseCacheFilterTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ResponseCacheFilterTest.cs
@@ -3,10 +3,13 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.ResponseCaching;
using Microsoft.AspNetCore.Routing;
+using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Internal
@@ -64,86 +67,113 @@ namespace Microsoft.AspNetCore.Mvc.Internal
ex.Message);
}
- public static IEnumerable