更改单个URL查询字符串值

时间:2010-09-28 14:42:42

标签: asp.net

我有一个ASP.NET页面,它在查询字符串中包含许多参数:

search.aspx?q=123&source=WebSearch

这将显示搜索结果的第一页。现在,在该页面的呈现中,我想显示一组链接,允许用户跳转到搜索结果中的不同页面。我只需附加&page=1&page=2

即可

它变得复杂的是我想保留原始页面中的输入查询字符串,除了我正在尝试更改的参数之外的每个参数。其他组件使用的url中可能还有其他参数,我尝试替换的值可能已经定义过,也可能没有定义:

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

在这种情况下,要生成指向下一页结果的链接,我希望将page=1更改为page=2,同时保持查询字符串的其余部分不变。

是否有内置方法可以执行此操作,还是需要手动执行所有字符串解析/重组?

5 个答案:

答案 0 :(得分:53)

您不能直接修改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 method会返回NameValueCollection(实际上它确实会返回HttpValueCollection,对结果进行编码as I mention in an answer to another question)。然后,您可以使用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类。

答案 1 :(得分:12)

你可以在没有重定向的所有开销的情况下做到这一点(这是不可忽视的)。我个人的偏好是使用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); 

答案 2 :(得分:5)

使用此QueryStringBuilder helper class,您可以获取当前的QueryString并调用Add方法来更改现有的键/值对...

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

答案 3 :(得分:0)

使用URIBuilder特别是link text查询属性

我相信你能做到你需要的。

答案 4 :(得分:0)

这至少在.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>