diff --git a/build/dependencies.props b/build/dependencies.props
index fb1b20df8d..06095e77c8 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -12,6 +12,7 @@
2.1.0-preview1-27965
2.1.0-preview1-27965
2.1.0-preview1-27965
+ 2.1.0-preview1-27965
2.1.0-preview1-27965
2.1.0-preview1-27965
2.1.0-preview1-27965
diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/CookieTempDataProviderOptions.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/CookieTempDataProviderOptions.cs
index 0b2badbd32..138105d7c8 100644
--- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/CookieTempDataProviderOptions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/CookieTempDataProviderOptions.cs
@@ -18,6 +18,11 @@ namespace Microsoft.AspNetCore.Mvc
HttpOnly = true,
SameSite = SameSiteMode.Strict,
+ // This cookie has been marked as non-essential because a user could use the SessionStateTempDataProvider,
+ // which is more common in production scenarios. Check the comment on CookieBuilder below
+ // for more information.
+ IsEssential = false,
+
// Some browsers do not allow non-secure endpoints to set cookies with a 'secure' flag or overwrite cookies
// whose 'secure' flag is set (http://httpwg.org/http-extensions/draft-ietf-httpbis-cookie-alone.html).
// Since mixing secure and non-secure endpoints is a common scenario in applications, we are relaxing the
@@ -33,7 +38,11 @@ namespace Microsoft.AspNetCore.Mvc
///
/// defaults to .
/// defaults to .
- /// defaults to true
+ /// defaults to true.
+ /// defaults to false, This property is only considered when a
+ /// user opts into the CookiePolicyMiddleware. If you are using this middleware and want to use
+ /// , then either set this property to true or
+ /// request user consent for non-essential cookies.
///
///
public CookieBuilder Cookie
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TempDataInCookiesUsingCookieConsentTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TempDataInCookiesUsingCookieConsentTest.cs
new file mode 100644
index 0000000000..c109e64a41
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TempDataInCookiesUsingCookieConsentTest.cs
@@ -0,0 +1,112 @@
+// 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 System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.Net.Http.Headers;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Mvc.FunctionalTests
+{
+ public class TempDataInCookiesUsingCookieConsentTest
+ : IClassFixture>
+ {
+ private readonly HttpClient _client;
+
+ public TempDataInCookiesUsingCookieConsentTest(
+ MvcTestFixture fixture)
+ {
+ _client = fixture.Client;
+ }
+
+ [Fact]
+ public async Task CookieTempDataProviderCookie_SetInResponse_OnGrantingConsent()
+ {
+ // Arrange
+ var nameValueCollection = new List>
+ {
+ new KeyValuePair("value", "Foo"),
+ };
+ var content = new FormUrlEncodedContent(nameValueCollection);
+ // This response would have the consent cookie which would be sent on rest of the requests here
+ var response = await _client.GetAsync("/TempData/GrantConsent");
+
+ // Act 1
+ response = await _client.SendAsync(GetPostRequest("/TempData/SetTempData", content, response));
+
+ // Assert 1
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+
+ // Act 2
+ response = await _client.SendAsync(GetRequest("/TempData/GetTempData", response));
+
+ // Assert 2
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.Equal("Foo", body);
+
+ // Act 3
+ response = await _client.SendAsync(GetRequest("/TempData/GetTempData", response));
+
+ // Assert 3
+ Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
+ }
+
+ [Fact]
+ public async Task CookieTempDataProviderCookie_NotSetInResponse_OnNoConsent()
+ {
+ // Arrange
+ var nameValueCollection = new List>
+ {
+ new KeyValuePair("value", "Foo"),
+ };
+ var content = new FormUrlEncodedContent(nameValueCollection);
+
+ // Act 1
+ var response = await _client.PostAsync("/TempData/SetTempData", content);
+
+ // Assert 1
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+
+ // Act 2
+ response = await _client.SendAsync(GetRequest("/TempData/GetTempData", response));
+
+ // Assert 2
+ Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
+ }
+
+ private HttpRequestMessage GetRequest(string path, HttpResponseMessage response)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, path);
+ SetCookieHeaders(request, response);
+ return request;
+ }
+
+ private HttpRequestMessage GetPostRequest(string path, HttpContent content, HttpResponseMessage response)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Post, path);
+ request.Content = content;
+ SetCookieHeaders(request, response);
+ return request;
+ }
+
+ private void SetCookieHeaders(HttpRequestMessage request, HttpResponseMessage response)
+ {
+ IEnumerable values;
+ if (response.Headers.TryGetValues("Set-Cookie", out values))
+ {
+ foreach (var cookie in SetCookieHeaderValue.ParseList(values.ToList()))
+ {
+ if (cookie.Expires == null || cookie.Expires >= DateTimeOffset.UtcNow)
+ {
+ request.Headers.Add("Cookie", new CookieHeaderValue(cookie.Name, cookie.Value).ToString());
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/BasicWebSite/BasicWebSite.csproj b/test/WebSites/BasicWebSite/BasicWebSite.csproj
index ca26efa240..b001b4aa71 100644
--- a/test/WebSites/BasicWebSite/BasicWebSite.csproj
+++ b/test/WebSites/BasicWebSite/BasicWebSite.csproj
@@ -13,5 +13,6 @@
+
diff --git a/test/WebSites/BasicWebSite/Controllers/TempDataController.cs b/test/WebSites/BasicWebSite/Controllers/TempDataController.cs
index a0fedabe02..1adeb1922a 100644
--- a/test/WebSites/BasicWebSite/Controllers/TempDataController.cs
+++ b/test/WebSites/BasicWebSite/Controllers/TempDataController.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using BasicWebSite.Filters;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
namespace BasicWebSite.Controllers
@@ -117,5 +118,11 @@ namespace BasicWebSite.Controllers
{
return TempData[nameof(UnhandledExceptionAndSettingTempData)]?.ToString();
}
+
+ [HttpGet]
+ public void GrantConsent()
+ {
+ HttpContext.Features.Get().GrantConsent();
+ }
}
}
diff --git a/test/WebSites/BasicWebSite/StartupWithCookieTempDataProviderAndCookieConsent.cs b/test/WebSites/BasicWebSite/StartupWithCookieTempDataProviderAndCookieConsent.cs
new file mode 100644
index 0000000000..7030e5eaaa
--- /dev/null
+++ b/test/WebSites/BasicWebSite/StartupWithCookieTempDataProviderAndCookieConsent.cs
@@ -0,0 +1,31 @@
+// 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.Builder;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace BasicWebSite
+{
+ public class StartupWithCookieTempDataProviderAndCookieConsent
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddMvc();
+
+ services.Configure(o =>
+ {
+ o.CheckConsentNeeded = httpContext => true;
+ });
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseDeveloperExceptionPage();
+
+ app.UseCookiePolicy();
+
+ app.UseMvcWithDefaultRoute();
+ }
+ }
+}
+