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?
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 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
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?
https://our.umbraco.com/forum/umbraco-9/105872-render-action-from-surface-controller
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?
https://github.com/aspnet/Announcements/issues/225 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?
https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing#session-state-and-distributed-cache 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 TempDataI use
System.Text.Json.JsonSerializer
as per: https://stackoverflow.com/questions/34638823/store-complex-object-in-tempdataI 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
is working on a reply...