Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect a POST request to a url maintaining model values in MVC

I have a fairly standard sort/filter/page search form but need control over the format of the url. The sort/filter/page parameters should all be part of the url so that, for example, the address could be emailed to someone.

When another filter parameter is added, a POST request is made. My controller method looks like this:

[HttpPost]
public ActionResult Search(string filterField,
                           Operator filterOperator, 
                           string filterValue, 
                           PeopleGroupSearchModel model);

The PeopleGroupSearchModel is populated from query string parameters. The filter* parameters are coming from the posted form values.

I would like to parse the provided filter values, which will then add a filter to a collection in the model called Filters. Then, take the updated model and convert it to the appropriate url and pass that as the response to the user.

So, for example, if they are on this page:

PeopleGroup/Search?page=4&sort=Country

... and POST:

  • filterField = PeopleGroupName
  • filterOperator = Equals
  • filterValue = Zulu

... once all the processing is done, the address in their browser should be something like:

PeopleGroup/Search?page=4&sort=Country&PeopleGroupName=Zulu&PeopleGroupName_op=Equals

So, more or less what I am trying to do:

[HttpGet]
public ActionResult Search(PeopleGroupSearchModel model)
{
    PeopleGroupData.Search(model);
    ViewData.Model = model;
    return View();
}

[HttpPost]
public ActionResult Search(string filterField,
                           Operator filterOperator,
                           string filterValue,
                           PeopleGroupSearchModel model)
{
    PeopleGroupFilter filter = ParseFilter(filterField, 
                                           filterOperator, 
                                           filterValue);
    model.Filters.Add(filter);
    return RedirectToAction("Search", ???);
}

I am very new to MVC, so if I am going about this completely the wrong way, please let me know!

like image 330
Dave Mateer Avatar asked Dec 07 '22 20:12

Dave Mateer


1 Answers

There are a couple of possibilities to implement the Redirect-After-Post pattern (which is what you are after here and which is a very good pattern IMHO) in ASP.NET MVC:

  1. Use TempData. In the POST action store the model inside TempData and redirect:

    TempData["model"] = model;
    return RedirectToAction("Search");
    

    and then inside the Search action check for TempData existence to fetch the model:

    PeopleGroupSearchModel model = TempData["model"] as PeopleGroupSearchModel;
    

    The drawback of this approach is that TempData is persisted only for a single redirect meaning that if the user hits F5 while on the Search GET action you are screwed. This could be alleviated by using Session instead. But of course Session introduces another problems of scalability. So I am not fan of this approach.

  2. Pass all properties on the request:

    return RedirectToAction("Search", new {
        prop1 = model.Prop1,
        prop2 = model.Prop2, 
        ....
    });
    

    Now when redirected to the Search GET action the Default model binder will be able to reconstruct the model. An obvious drawback of this approach is that if your model has many properties and even worse properties of complex types this could quickly become a cumbersome solution. You could probably serialize the model using some text format such as JSON as a query string parameter. Of course query string parameters are limited between different browsers so this could also be a no-no.

  3. Persist the model in some data storage and retrieve an unique id so that it can later be retrieved from this storage:

    int id = Persist(model);
    return RedirectToAction("Search", new { id = id });
    

    And then in the GET action retrieve the model from this very same persistence storage using the id. I like this approach and use it most of the time. If persisting to the aforementioned datastore is expensive you could use caching.

like image 191
Darin Dimitrov Avatar answered Dec 28 '22 22:12

Darin Dimitrov