diff --git a/ResponseCaching.sln b/ResponseCaching.sln
index c052708fa0..43b8d0f0b8 100644
--- a/ResponseCaching.sln
+++ b/ResponseCaching.sln
@@ -20,6 +20,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Respon
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ResponseCaching", "src\Microsoft.AspNetCore.ResponseCaching\Microsoft.AspNetCore.ResponseCaching.xproj", "{D1031270-DBD3-4F02-A3DC-3E7DADE8EBE6}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ResponseCaching.Abstractions", "src\Microsoft.AspNetCore.ResponseCaching.Abstractions\Microsoft.AspNetCore.ResponseCaching.Abstractions.xproj", "{2D1022E8-CBB6-478D-A420-CB888D0EF7B7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -38,6 +40,10 @@ Global
{D1031270-DBD3-4F02-A3DC-3E7DADE8EBE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1031270-DBD3-4F02-A3DC-3E7DADE8EBE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1031270-DBD3-4F02-A3DC-3E7DADE8EBE6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D1022E8-CBB6-478D-A420-CB888D0EF7B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D1022E8-CBB6-478D-A420-CB888D0EF7B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D1022E8-CBB6-478D-A420-CB888D0EF7B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D1022E8-CBB6-478D-A420-CB888D0EF7B7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -46,5 +52,6 @@ Global
{1139BDEE-FA15-474D-8855-0AB91F23CF26} = {C51DF5BD-B53D-4795-BC01-A9AB066BF286}
{151B2027-3936-44B9-A4A0-E1E5902125AB} = {89A50974-E9D4-4F87-ACF2-6A6005E64931}
{D1031270-DBD3-4F02-A3DC-3E7DADE8EBE6} = {367AABAF-E03C-4491-A9A7-BDDE8903D1B4}
+ {2D1022E8-CBB6-478D-A420-CB888D0EF7B7} = {367AABAF-E03C-4491-A9A7-BDDE8903D1B4}
EndGlobalSection
EndGlobal
diff --git a/samples/ResponseCachingSample/project.json b/samples/ResponseCachingSample/project.json
index 3ddb9bb33c..8fa43edb22 100644
--- a/samples/ResponseCachingSample/project.json
+++ b/samples/ResponseCachingSample/project.json
@@ -1,7 +1,7 @@
{
"version": "1.1.0-*",
"dependencies": {
- "Microsoft.AspNetCore.ResponseCaching": "0.1.0-*",
+ "Microsoft.AspNetCore.ResponseCaching": "1.0.0-*",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0-*",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*",
"Microsoft.Extensions.Caching.Memory": "1.1.0-*"
diff --git a/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/IResponseCacheFeature.cs b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/IResponseCacheFeature.cs
new file mode 100644
index 0000000000..2306c410f8
--- /dev/null
+++ b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/IResponseCacheFeature.cs
@@ -0,0 +1,18 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.ResponseCaching
+{
+ ///
+ /// A feature for configuring additional response cache options on the HTTP response.
+ ///
+ public interface IResponseCacheFeature
+ {
+ ///
+ /// Gets or sets the query keys used by the response cache middleware for calculating secondary vary keys.
+ ///
+ StringValues VaryByQueryKeys { get; set; }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/Microsoft.AspNetCore.ResponseCaching.Abstractions.xproj b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/Microsoft.AspNetCore.ResponseCaching.Abstractions.xproj
new file mode 100644
index 0000000000..d06ce2e8f9
--- /dev/null
+++ b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/Microsoft.AspNetCore.ResponseCaching.Abstractions.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 2d1022e8-cbb6-478d-a420-cb888d0ef7b7
+ Microsoft.AspNetCore.ResponseCaching.Abstractions
+ .\obj
+ .\bin\
+ v4.5.2
+
+
+
+ 2.0
+
+
+
diff --git a/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..32dcddfc57
--- /dev/null
+++ b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Reflection;
+using System.Resources;
+
+[assembly: AssemblyMetadata("Serviceable", "True")]
+[assembly: NeutralResourcesLanguage("en-us")]
+[assembly: AssemblyCompany("Microsoft Corporation.")]
+[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
+[assembly: AssemblyProduct("Microsoft ASP.NET Core")]
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/project.json b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/project.json
new file mode 100644
index 0000000000..ee4622c44c
--- /dev/null
+++ b/src/Microsoft.AspNetCore.ResponseCaching.Abstractions/project.json
@@ -0,0 +1,31 @@
+{
+ "version": "1.0.0-*",
+ "buildOptions": {
+ "warningsAsErrors": true,
+ "keyFile": "../../tools/Key.snk",
+ "xmlDoc": true
+ },
+ "description": "ASP.NET Core response caching middleware abstractions and feature interface definitions.",
+ "packOptions": {
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aspnet/ResponseCaching"
+ },
+ "tags": [
+ "aspnetcore",
+ "cache",
+ "caching"
+ ]
+ },
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "1.1.0-*"
+ },
+ "frameworks": {
+ "net451": {},
+ "netstandard1.3": {
+ "dependencies": {
+ "NETStandard.Library": "1.6.1-*"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheHttpContextExtensions.cs b/src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheHttpContextExtensions.cs
deleted file mode 100644
index d8349bf594..0000000000
--- a/src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheHttpContextExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Microsoft.AspNetCore.Http;
-
-namespace Microsoft.AspNetCore.ResponseCaching
-{
- public static class ResponseCacheHttpContextExtensions
- {
- public static ResponseCacheFeature GetResponseCacheFeature(this HttpContext httpContext)
- {
- return httpContext.Features.Get();
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Internal/InternalHttpContextExtensions.cs b/src/Microsoft.AspNetCore.ResponseCaching/Internal/InternalHttpContextExtensions.cs
deleted file mode 100644
index e76aa83a68..0000000000
--- a/src/Microsoft.AspNetCore.ResponseCaching/Internal/InternalHttpContextExtensions.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using Microsoft.AspNetCore.Http;
-
-namespace Microsoft.AspNetCore.ResponseCaching.Internal
-{
- internal static class InternalHttpContextExtensions
- {
- internal static void AddResponseCacheFeature(this HttpContext httpContext)
- {
- if (httpContext.GetResponseCacheFeature() != null)
- {
- throw new InvalidOperationException($"Another instance of {nameof(ResponseCacheFeature)} already exists. Only one instance of {nameof(ResponseCacheMiddleware)} can be configured for an application.");
- }
- httpContext.Features.Set(new ResponseCacheFeature());
- }
-
- internal static void RemoveResponseCacheFeature(this HttpContext httpContext)
- {
- httpContext.Features.Set(null);
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheExtensions.cs b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheExtensions.cs
similarity index 100%
rename from src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheExtensions.cs
rename to src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheExtensions.cs
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheFeature.cs b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheFeature.cs
index eec1a64887..374338a688 100644
--- a/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheFeature.cs
+++ b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheFeature.cs
@@ -5,7 +5,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.ResponseCaching
{
- public class ResponseCacheFeature
+ public class ResponseCacheFeature : IResponseCacheFeature
{
public StringValues VaryByQueryKeys { get; set; }
}
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs
index c7939b82c8..6be81a9578 100644
--- a/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs
+++ b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs
@@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Create the cache entry now
var response = context.HttpContext.Response;
var varyHeaders = new StringValues(response.Headers.GetCommaSeparatedValues(HeaderNames.Vary));
- var varyQueryKeys = context.HttpContext.GetResponseCacheFeature()?.VaryByQueryKeys ?? StringValues.Empty;
+ var varyQueryKeys = context.HttpContext.Features.Get()?.VaryByQueryKeys ?? StringValues.Empty;
context.CachedResponseValidFor = context.ResponseCacheControlHeaderValue.SharedMaxAge ??
context.ResponseCacheControlHeaderValue.MaxAge ??
(context.ResponseExpires - context.ResponseTime.Value) ??
@@ -325,7 +325,12 @@ namespace Microsoft.AspNetCore.ResponseCaching
context.HttpContext.Features.Set(new SendFileFeatureWrapper(context.OriginalSendFileFeature, context.ResponseCacheStream));
}
- context.HttpContext.AddResponseCacheFeature();
+ // Add IResponseCacheFeature
+ if (context.HttpContext.Features.Get() != null)
+ {
+ throw new InvalidOperationException($"Another instance of {nameof(ResponseCacheFeature)} already exists. Only one instance of {nameof(ResponseCacheMiddleware)} can be configured for an application.");
+ }
+ context.HttpContext.Features.Set(new ResponseCacheFeature());
}
internal static void UnshimResponseStream(ResponseCacheContext context)
@@ -336,7 +341,8 @@ namespace Microsoft.AspNetCore.ResponseCaching
// Unshim IHttpSendFileFeature
context.HttpContext.Features.Set(context.OriginalSendFileFeature);
- context.HttpContext.RemoveResponseCacheFeature();
+ // Remove IResponseCacheFeature
+ context.HttpContext.Features.Set(null);
}
internal static bool ContentIsNotModified(ResponseCacheContext context)
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheServiceCollectionExtensions.cs
similarity index 100%
rename from src/Microsoft.AspNetCore.ResponseCaching/Extensions/ResponseCacheServiceCollectionExtensions.cs
rename to src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheServiceCollectionExtensions.cs
diff --git a/src/Microsoft.AspNetCore.ResponseCaching/project.json b/src/Microsoft.AspNetCore.ResponseCaching/project.json
index 5adf0b7360..04f2eae5c3 100644
--- a/src/Microsoft.AspNetCore.ResponseCaching/project.json
+++ b/src/Microsoft.AspNetCore.ResponseCaching/project.json
@@ -1,5 +1,5 @@
{
- "version": "0.1.0-*",
+ "version": "1.0.0-*",
"buildOptions": {
"warningsAsErrors": true,
"allowUnsafe": true,
@@ -24,6 +24,7 @@
"dependencies": {
"Microsoft.AspNetCore.Http": "1.1.0-*",
"Microsoft.AspNetCore.Http.Extensions": "1.1.0-*",
+ "Microsoft.AspNetCore.ResponseCaching.Abstractions": "1.0.0-*",
"Microsoft.Extensions.Caching.Memory": "1.1.0-*",
"Microsoft.Extensions.Logging.Abstractions": "1.1.0-*",
"Microsoft.Extensions.TaskCache.Sources": {
diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/HttpContextInternalExtensionTests.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/HttpContextInternalExtensionTests.cs
deleted file mode 100644
index 8efd416d16..0000000000
--- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/HttpContextInternalExtensionTests.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.ResponseCaching.Internal;
-using Xunit;
-
-namespace Microsoft.AspNetCore.ResponseCaching.Tests
-{
- public class HttpContextInternalExtensionTests
- {
- [Fact]
- public void AddingSecondResponseCacheFeature_Throws()
- {
- var httpContext = new DefaultHttpContext();
-
- // Should not throw
- httpContext.AddResponseCacheFeature();
-
- // Should throw
- Assert.ThrowsAny(() => httpContext.AddResponseCacheFeature());
- }
- }
-}
diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs
index 9e251dc9b1..f2005ff54f 100644
--- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs
+++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs
@@ -433,8 +433,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB", "HEADERc" });
- context.HttpContext.AddResponseCacheFeature();
- context.HttpContext.GetResponseCacheFeature().VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" });
+ context.HttpContext.Features.Set(new ResponseCacheFeature()
+ {
+ VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" })
+ });
var cachedVaryByRules = new CachedVaryByRules()
{
Headers = new StringValues(new[] { "HeaderA", "HeaderB" }),
@@ -462,8 +464,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var context = TestUtils.CreateTestContext();
context.HttpContext.Response.Headers[HeaderNames.Vary] = new StringValues(new[] { "headerA", "HEADERB" });
- context.HttpContext.AddResponseCacheFeature();
- context.HttpContext.GetResponseCacheFeature().VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" });
+ context.HttpContext.Features.Set(new ResponseCacheFeature()
+ {
+ VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" })
+ });
var cachedVaryByRules = new CachedVaryByRules()
{
VaryByKeyPrefix = FastGuid.NewGuid().IdString,
@@ -669,6 +673,19 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
LoggedMessage.ResponseNotCached);
}
+ [Fact]
+ public void ShimResponseStream_SecondInvocation_Throws()
+ {
+ var middleware = TestUtils.CreateTestMiddleware();
+ var context = TestUtils.CreateTestContext();
+
+ // Should not throw
+ middleware.ShimResponseStream(context);
+
+ // Should throw
+ Assert.ThrowsAny(() => middleware.ShimResponseStream(context));
+ }
+
[Fact]
public void GetOrderCasingNormalizedStringValues_NormalizesCasingToUpper()
{
diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheTests.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheTests.cs
index bc473d12a5..68c7f2ab86 100644
--- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheTests.cs
+++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheTests.cs
@@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = "query";
+ context.Features.Get().VaryByQueryKeys = "query";
await TestUtils.TestRequestDelegate(context);
});
@@ -126,7 +126,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "QueryA", "queryb" };
+ context.Features.Get().VaryByQueryKeys = new[] { "QueryA", "queryb" };
await TestUtils.TestRequestDelegate(context);
});
@@ -148,7 +148,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "*" };
+ context.Features.Get().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
@@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "QueryB", "QueryA" };
+ context.Features.Get().VaryByQueryKeys = new[] { "QueryB", "QueryA" };
await TestUtils.TestRequestDelegate(context);
});
@@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "*" };
+ context.Features.Get().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
@@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = "query";
+ context.Features.Get().VaryByQueryKeys = "query";
await TestUtils.TestRequestDelegate(context);
});
@@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "QueryA", "QueryB" };
+ context.Features.Get().VaryByQueryKeys = new[] { "QueryA", "QueryB" };
await TestUtils.TestRequestDelegate(context);
});
@@ -258,7 +258,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
{
var builders = TestUtils.CreateBuildersWithResponseCache(requestDelegate: async (context) =>
{
- context.GetResponseCacheFeature().VaryByQueryKeys = new[] { "*" };
+ context.Features.Get().VaryByQueryKeys = new[] { "*" };
await TestUtils.TestRequestDelegate(context);
});
diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCaching.Tests/project.json
index 7eefd0a959..7932f53e10 100644
--- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/project.json
+++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/project.json
@@ -5,7 +5,7 @@
},
"dependencies": {
"dotnet-test-xunit": "2.2.0-*",
- "Microsoft.AspNetCore.ResponseCaching": "0.1.0-*",
+ "Microsoft.AspNetCore.ResponseCaching": "1.0.0-*",
"Microsoft.AspNetCore.TestHost": "1.1.0-*",
"Microsoft.Extensions.Logging.Testing": "1.1.0-*",
"xunit": "2.2.0-*"