umbraco/Umbraco.Forms.Issues

TempData for Rendering Forms Scripts

Closed this issue · 3 comments

Recently while configuring Cloudflare proxy in front of an Umbraco site, we found pages could not be cached due to the presence of a Set-Cookie header in the response.

This was found to be caused by including the docs recommended code for rendering form scripts, which was placed in our global layout cshtml. The same applies if using the tag helper approach.

Since ASP.NET Core 2.0 the default TempData provider has used cookies to store values, or can be configured to use Session storage if desired (which likely also uses cookies).

Of course we only want these scripts loaded on pages where Umbraco Forms are present, but even checking if a value exists in TempData causes the Set-Cookie header to be added.

It seems the goal is to share the form IDs being loaded so the scripts can be loaded elsewhere. Perhaps there are other uses I'm not aware of...

My question is: why has TempData been chosen for this purpose? Could something like the HttpContext.Items dictionary (which lives within the request) be used instead to avoid this unnecessary cookie? I believe this approach is also used by Smidge etc.

Simply changing away from TempData would be a breaking change, but I see little harm in having both TempData and HttpContext.Items options available until a suitable time...

For now we have opted to add our entry into HttpContext.Items whenever a form is rendered that we can check for in the layout.


This item has been added to our backlog AB#36435

I don't know the answer to the question I'm afraid... this was implemented before my time and it's just been carried over as is from version to version. Now you point it out though, it does seem like HttpContext.Items would work just fine and would be a better option. We'll give it a try to see if it works as expected, and if so, I'm considering we could make it a configurable option to use TempData or HttpContext.Items for this tracking of forms rendered on the page for the purpose of rendering the appropriate scripts and form data.

That way you, or anyone else, can swap to use HttpContext.Items, and we can make this the default from Forms 14.

This will be available in the next patch releases for Forms 12 and 13.

You'll be able to set the following in configuration:

"Umbraco": {
  "Forms": {
    "Options": {
      "TrackRenderedFormsStorageMethod": "TempData|HttpContextItems"
    },

TempData will be the default but you can set to HttpContextItems to use HttpContext.Items instead. We'll likely make HttpContextItems the default in Forms 14.

With that set you'll be able to render the scripts using:

  if (Context.Items.TryGetValue("UmbracoForms", out object? formIdsObject) && formIdsObject is IEnumerable<Guid> formIds)
  {
      foreach (var formId in formIds)
      {
          @await Component.InvokeAsync("RenderFormScripts", new { formId, theme = "default" })
      }
  }

Or just use the tag helper which will use the appropriate storage method depending on configuration:

<umb-forms-render-scripts theme="default" />

That's awesome, thanks @AndyButland!