2010-09-28 35 views
23

我有一个ASP.NET页面这需要在查询字符串中的一些参数:更改单个URL查询字符串值

search.aspx?q=123&source=WebSearch 

这将显示搜索结果的第一页。现在,在该页面的呈现中,我想显示一组允许用户跳转到搜索结果中的不同页面的链接。我可以简单地通过追加&page=1&page=2

这里它变得复杂的是,我想保留从原始页面的输入查询字符串除了我想要改变的每个参数。可能还有其他的参数由其他组件所使用的网址,我试图取代的价值可能会或可能不会已经被定义为:

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

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

是否有内置的方法来做到这一点,或者我需要手动执行所有的字符串解析/重组?

回答

0

使用URIBuilder具体的link text查询物业

我相信,做你所需要的。

+0

UriBuilder让我改变了请求URL的整个查询组件,我想要做的是改变/ URL中添加一个特定的查询参数。 – star 2010-09-28 14:58:34

5

使用此QueryStringBuilder helper class,你可以抓住当前的查询字符串,并调用Add方法来改变现有的键/值对...

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

好的资源。谢谢! – Mark1270287 2013-10-26 22:59:19

+0

新版本使用格式: string newQueryString = QueryString.Current.Add(“page”,“2”)。ToString(); – Mark1270287 2013-10-26 23:11:13

51

不能直接修改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删除值。最后,在名称NameValueCollection上调用ToString()name1=value1&name2=value2查询字符串就绪格式返回名称值对。一旦你有它追加到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类。

+0

其实你可以直接设置,反射让你修改这个。但我个人同意使用NVC。 – annakata 2010-09-28 15:25:19

+0

@annakata刚刚阅读您的回复。有趣的方法,而不是想到的第一件事。 – 2010-09-28 15:29:51

+0

ToString方法还有一个问题。它不正确地处理具有多个值的键。而不是使用逗号分隔列表,它重复键对=值。例如,如果添加了两个值为value1,value2的条目参数,您将得到结果param = value1&param = value2,而不是param = value1,value2。 – Stoune 2015-11-20 12:26:41

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); 
+0

这是一个非常好的解决方案,我不确定它是否可以工作,但为我做了诀窍。我无法真正负担基于我的架构的response.redirect,并可以避免使用这种方法。谢谢! – 2012-12-12 00:21:44

+0

我收到错误“'PropertyInfo'是'反射'中的一种类型,不能用作表达式。” – jbyrd 2016-10-12 13:59:43

0

这是非常武断的,在.NET的核心。而这一切都归结为asp-all-route-data

考虑以下简单的例子(从“分页程序”视图模型采取我用在几乎每一个项目):

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>