sessionasp.net-corecookiestempdata

TempData Cookie Issue. The size of the request headers is too long


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

enter image description here

and several cookies were created (Chrome Developer Tools > Application > Storage > Cookies)

enter image description here

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 ?


Solution

  • 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>
    

    DefaultTempDataSerializer supported types

    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);
    }