Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at

  • Phil Makower 3 posts 23 karma points
    Apr 22, 2024 @ 12:36
    Phil Makower

    SurfaceController GET and POST v7 code to v13

    I have an "advanced search" form on a v7 site which shows a table of products, with a sidebar of filters to narrow down the list This is done using Html.RenderAction(), and a SurfaceController.

    The default (GET/POST etc) action on the controller populates the full table, checking TEMPDATA for possible MODEL (which presumably picks up the MODEL from the POST below), and returns PartialView(). The Partial includes Html.BeginUmbracoForm specifying the controller and action name,

    The POST action performs the search if the modelstate is valid, sets the MODEL in TEMPDATA, and returns RedirectToCurrentUmbracoPage().

    How do I do this in Umbraco 13? I have not been able to find an example where the form is populated with defaults and changed by the POST?

    Tried adding [ViewComponent] attribute to the controller. and an Invoke() method. This takes the current page as a parameter. The template calls @await Component.InvokeAsync(name)

    The full results list is shown.

    However, when I POST the form, I get a 400 bad request - Request too long. There seem to be multiple cookies (6): .AspNetCore.Mvc.CookieTempDataProvider .AspNetCore.Mvc.CookieTempDataProviderC1 etc, 4016 bytes each

    Are these because I am adding to TEMPDATA each time? It turns out that in 2017(!) the default TempData storage provider in MVC changed from SessionStateTempDataProvider to CookieTempDataProvider

    The example code shows we change two places to set the provider to SessionStateTempDataProvider, ConfigureServices() and Configure()

    There does NOT seem to be a way to do this in Startup.cs? Says "The distributed cache is used by the session in your application, which is used by the default TempDataProvider in MVC." which I think is WRONG (since 2017!)

    OK got it working now. My Model included a list of the results (over 600 items by default!) In v7, the Session was used to store the TempData, which had plenty of room for all this. In v13, cookie/s are used to store the TempData, so there is NOT plenty of rooom (4Kb max per cookie)

    I have created a separate TempDataModel to hold just the properties I need to store in TempData, create a populate that model in the POST, then add that to TempData

    I use System.Text.Json.JsonSerializer as per:

    I the INVOKE method in the same controller as the POST. I first check TempData?.Peek<TempDataFilterModel>("Model") returns non-null value (where TempDataFilterModel is my Model and "Model" is the TempData key I stored it to)

    TempDataFilterModel is PUBLIC, and contains only PUBLIC properties with GET and SET. It also includes a PUBLIC parameterless constructor, as apparently required by JSON deserializer. It has ONE string, which is assigned in the constructor to String.Empty.

    However, this actually returns NULL even when there is a value in TempData

    My .Peek<T> extension stores the object returned from TempData and before deserialization into a static property which I have a static method to return the value of (so it's read only outside the static class)

    I can see that this returns the JSON as expected! For some reason, the deserialize does not work!

    I create a default Model always.

    I can use JsonNode.Parse() to parse the JSON into a JsonNode object, and read the individual properties and set the corresponding properties in the Model to match

    Then when I use the model to run the DB query to filter the results, I get either the full default list as expected when none of the filters have been set, or a reduced list when one or more of the filters has been set

Please Sign in or register to post replies

Write your reply to: