In Controller, I save a collection of errors into cookies
via TempData
var messages = new List<Message>();
...
TempData.Put("Errors", messages);
TempData.Put is an extension method
public static class TempDataExtensions
{
public static void Put<T>(this ITempDataDictionary tempData, string key, T value) where T : class
{
tempData[key] = JsonConvert.SerializeObject(value);
}
public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
{
tempData.TryGetValue(key, out object o);
return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
}
}
When HTML is loaded, I see
and several cookies were created (Chrome Developer Tools > Application > Storage > Cookies)
The issue I think, is that total size of Cookies is hitting some Cookie Size limit somewhere.
So I have two questions :
Is it possible to change the cookie size limit (in web.config for example) ?
Is it possible to use session instead of cookies for TempData
?
I tried the second approach and if I change the startup.cs file
\\ ConfigureServices method
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddSessionStateTempDataProvider();
services.AddSession();
\\ Configure method
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
The TempData are still using Cookies, do I forgot some setting somewhere ?
You can use HTTP cookies or session state as storage mechanism for TempData
. The cookie-based TempData
provider is the default.
You can read more about Choose a TempData provider.
Based on the following example from docs you can enable the session-based TempData
provider, by calling AddSessionStateTempDataProvider
extension method. The order of middleware is important.
Be aware of
DefaultTempDataSerializer
limitations pointed out at bottom of this answer.
Example
Hers is a working deployment using the following setup that I have for Srartup:
public class Startup
{
public Startup(IConfiguration configuration) { Configuration = configuration; }
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddSessionStateTempDataProvider();
services.AddSession();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else {
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSession();
app.UseMvc(routes => {
routes.MapRoute(name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
The HomeController:
public class HomeController : Controller
{
public IActionResult Index()
{
TempData["LargeData"] = new string('a', 1 * 1024 * 1024);
return View();
}
}
And the Index View:
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome - @(((string)TempData["LargeData"]).Length)</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">
building Web apps with ASP.NET Core</a>.</p>
</div>
Be aware of DefaultTempDataSerializer
supported type limitations:
public override bool CanSerializeType(Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
type = Nullable.GetUnderlyingType(type) ?? type;
return
type.IsEnum ||
type == typeof(int) ||
type == typeof(string) ||
type == typeof(bool) ||
type == typeof(DateTime) ||
type == typeof(Guid) ||
typeof(ICollection<int>).IsAssignableFrom(type) ||
typeof(ICollection<string>).IsAssignableFrom(type) ||
typeof(IDictionary<string, string>).IsAssignableFrom(type);
}