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

1

14

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 ?

Cana answered 29/1, 2020 at 15:38 Comment(3)
As you mentioned, normally if we need to store large amounts of data in TempData, we can use the session provider instead. Besides, after you enabled session-based TempData provider, please try to clear existing cookies using browser F12 developer tool then browse your site to check if it work well.Tetrabranchiate
Hello Han, how can I be assured, that session provider works ? The cookies are still being created, therefore I posted this question.Cana
Yes you can use Session based temp data.Mishmash
M
10

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);
}
Mishmash answered 20/2, 2020 at 11:0 Comment(6)
Reza, thank you, I have it as you. On localhost it works, but after publishing to IIS it throw error 400, what now ? :/Cana
Which Version of ASP.NET CORE are you using?Mishmash
version 2.1 and compability version is also CompatibilityVersion.Version_2_1. I verified that no cookies are generated when using localhost IIS, but after switch to development IIS, it still uses CookieTempProvider.Cana
Updated the answer with a working solution and a working deployment. Also be aware of DefaultTempDataSerializer supported type limitations.Mishmash
It works ! I put ashes on my head, because I also had services.AddSingleton<ITempDataProvider, CookieTempDataProvider>(); in the startup.cs which negated session settings. I don't understand that I didn't notice it earlier.Cana
Oops! You should have copied the code into a clean project. Anyway, the good thing is your problem has been solved. Thanks for the feedback :)Mishmash

© 2022 - 2024 — McMap. All rights reserved.