Изменить значение строки запроса одиночного URL-адреса

У меня есть страница ASP.NET, которая принимает ряд параметров в строке запроса:

search.aspx?q=123&source=WebSearch

Это отобразит первую страницу результатов поиска. Теперь, в рамках рендеринга этой страницы, я хочу отобразить набор ссылок, которые позволяют пользователю переходить на разные страницы в результатах поиска. Я могу сделать это просто append &page=1 или &page=2 и т.д.

Там, где это усложняется, я хочу сохранить строку входных запросов на исходной странице для каждого параметра, кроме той, которую я пытаюсь изменить. Могут быть другие параметры в URL-адресе, используемом другими компонентами, и значение, которое я пытаюсь заменить, может или не может быть определено:

search.aspx?q=123&source=WebSearch&page=1&Theme=Blue

В этом случае для создания ссылки на следующую страницу результатов я хочу изменить page=1 на page=2, оставив остальную строку запроса без изменений.

Есть ли встроенный способ сделать это, или мне нужно выполнить всю парсинг/рекомбинацию строк вручную?

Ответ 1

Вы не можете изменить QueryString напрямую, так как он доступен только для чтения. Вам нужно будет получить значения, изменить их, а затем вернуть обратно. Попробуйте следующее:

var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
nameValues.Set("page", "2");
string url = Request.Url.AbsolutePath;
string updatedQueryString = "?" + nameValues.ToString();
Response.Redirect(url + updatedQueryString);

Метод ParseQueryString возвращает NameValueCollection (на самом деле он действительно возвращает HttpValueCollection, который кодирует результаты, как я упоминаю в ответе на другой вопрос). Затем вы можете использовать метод Set для обновления значения. Вы также можете использовать метод Add, чтобы добавить новый, или Remove, чтобы удалить значение. Наконец, вызов ToString() в имени NameValueCollection возвращает пары значений имени в формате name1=value1&name2=value2 querystring ready. После того, как вы добавите его в URL-адрес и перенаправляете.

В качестве альтернативы вы можете добавить новый ключ или изменить существующий с помощью индексатора:

nameValues["temp"] = "hello!"; // add "temp" if it didn't exist
nameValues["temp"] = "hello, world!"; // overwrite "temp"
nameValues.Remove("temp"); // can't remove via indexer

Вам может понадобиться добавить using System.Collections.Specialized;, чтобы использовать класс NameValueCollection.

Ответ 2

Вы можете сделать это без всех накладных расходов на перенаправление (что не является незначительным). Мое личное предпочтение - работать с NameValueCollection, который действительно есть, но используя отражение:

// reflect to readonly property 
PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 

// make collection editable 
isReadOnly.SetValue(this.Request.QueryString, false, null); 

// remove 
this.Request.QueryString.Remove("foo"); 

// modify 
this.Request.QueryString.Set("bar", "123"); 

// make collection readonly again 
isReadOnly.SetValue(this.Request.QueryString, true, null); 

Ответ 3

Используя этот класс-помощник QueryStringBuilder, вы можете захватить текущую QueryString и вызвать метод Add для изменения существующей пары ключ/значение...

//before: "?id=123&page=1&sessionId=ABC"
string newQueryString = QueryString.Current.Add("page", "2");
//after: "?id=123&page=2&sessionId=ABC"

Ответ 4

Используйте URIBuilder В частности, текст ссылки Свойство запроса

Я считаю, что делает то, что вам нужно.

Ответ 5

Это довольно произвольно, по крайней мере, в .NET Core. И все это сводится к asp-all-route-data

Рассмотрим следующий тривиальный пример (взятый из модели просмотра "paginator", которую я использую практически в каждом проекте):

public class SomeViewModel 
{

    public Dictionary<string, string> NextPageLink(IQueryCollection query)
    {
        /*
         * NOTE: how you derive the "2" is fully up to you
         */
        return ParseQueryCollection(query, "page", "2");
    }

    Dictionary<string, string> ParseQueryCollection(IQueryCollection query, string replacementKey, string replacementValue)
    {
        var dict = new Dictionary<string, string>()
        {
            { replacementKey, replacementValue }
        };

        foreach (var q in query)
        {
            if (!string.Equals(q.Key, replacementKey, StringComparison.OrdinalIgnoreCase))
            {
                dict.Add(q.Key, q.Value);
            }
        }

        return dict;
    }
}

Затем, чтобы использовать в своем представлении, просто передайте метод текущей коллекции запросов запроса из Context.Request:

<a asp-all-route-data="@Model.NextPageLink(Context.Request.Query)">Next</a>