Redirection with params - No query string I have a products page with a search box. When a search is submitted there's a redirection to a search results page.
If another search is submitted then the query string remains intact (results are populated via ajax).
So what I've done is running twice to the server, one time using ajax to set the Session value and another for the redirect itself:

Products page

function search() {
    //get the search query text
    var query = $('#productSearchInput').val();
    //url to a method on the search controller
    var url = 'http://SearchPageUrl' + '/SetSearchQuery';
    //set the session value
    $.get(url, { query: query })
        .done(function () {
            //actual redirect
            window.location.href = 'http://SearchPageUrl';
        });
    }


Search results controller - set the session value

public void SetSearchQuery(string query)
{
    System.Web.HttpContext.Current.Session["searchQuery"] = WebUtility.HtmlDecode(query);
}


Search page entry point

public ActionResult Index()
{
    string query = System.Web.HttpContext.Current.Session["searchQuery"].ToString();
    ViewBag.query = query;

    //get the products...
    //var results = GetProducts(query);
    return View("~/Views/something/SearchResults.cshtml", results);
}


So this works but it feels like a lot of not so maintainable or efficient implementation.
How can I make it better?
Using the session to store this is icky, since a user may have multiple tabs open. I.e. multiple searches, but only one that your server remembers.

Anyway, if I understand this correctly, try this:

The first time a user hits the results page, have it pre-populated with results. Don't load anything via ajax; it should already be there. However, the results page should also have a different handler for the user clicking search/submitting the form.

Anywhere else on the site, searching should just send you to the results page. On the results page, however, the search function does its AJAX thing, and fetches the results, replacing whatever's on the page.

Now, to update the displayed URL, use pushState and listen for popState events too, to update the address bar, and keep a "correct" browsing history.

So on your results page, you'll want something like this for your search handler:

function search() {
    // get the search query text
    var query = $('#productSearchInput').val();

    // url for the search page
    var base = 'http://SearchPageUrl';

    // create the new URL to display in the address bar/history
    var url = base + '?query=' + encodeURIComponent(query);

    // fetch results for the new query
    $.get(base, { query: query })
        .done(function (data) {
            // push the url to the address bar/history
            history.pushState({query: query}, "Search results", url);

            // insert new results into the page ...
        });
}


And on any other page, you want no JS. Just a plain GET form pointing at the results page.



Alternatively, if I misunderstood and you don't want queries in the address bar at all, simply do what randcd suggested in the comments: Use POST. Make the search form's method POST, and use $.post() when you need to update results.