【问题标题】:Change Single URL query string value更改单个 URL 查询字符串值
【发布时间】:2011-04-18 08:31:11
【问题描述】:

我有一个 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,同时保持查询字符串的其余部分不变。

有没有内置的方法可以做到这一点,还是我需要手动进行所有的字符串解析/重新组合?

【问题讨论】:

    标签: asp.net


    【解决方案1】:

    使用 URIBuilder 特别是 link textQuery 属性

    我相信这可以满足您的需求。

    【讨论】:

    • UriBuilder 让我可以更改请求 url 的整个查询组件,我要做的是在 url 中更改/添加一个特定的查询参数。
    【解决方案2】:

    使用这个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"
    

    【讨论】:

    • 不错的资源。谢谢!
    • 新版本使用格式:string newQueryString = QueryString.Current.Add("page", "2").ToString();
    【解决方案3】:

    您不能直接修改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 类。

    【讨论】:

    • 其实可以直接设置,反射让你修改这个。不过,我个人同意使用 NVC。
    • @annakata 刚刚阅读了您的回复。有趣的方法,不是首先想到的。
    • ToString 方法还有一个问题。它错误地处理具有多个值的键。它不是制作逗号分隔的列表,而是复制对 key=value。例如,如果您两次使用值 value1、value2 添加条目参数,您将得到结果 param=value1&param=value2 而不是 param=value1,value2。
    【解决方案4】:

    您可以在没有重定向开销的情况下执行此操作(这不是小问题)。我个人的偏好是使用查询字符串确实是的 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); 
    

    【讨论】:

    • 这是一个非常好的解决方案,我不确定它是否有效,但对我有用。我真的负担不起基于我的架构的 response.redirect 并且可以通过这种方法避免。谢谢!
    • 我收到错误消息“'PropertyInfo' 是 'Reflection' 中的一种类型,不能用作表达式。”
    【解决方案5】:

    这是相当随意的,至少在 .NET Core 中是这样。这一切都归结为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>
    

    【讨论】:

      猜你喜欢
      • 2016-10-29
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 2014-01-28
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多