【问题标题】:Parse and modify a query string in .NET Core在 .NET Core 中解析和修改查询字符串
【发布时间】:2015-07-11 15:18:53
【问题描述】:

我得到一个包含查询字符串的绝对 URI。我希望安全地将值附加到查询字符串,并更改现有参数。

我不希望使用&foo=bar,或者使用正则表达式,URI 转义很棘手。相反,我想使用我知道可以正确执行此操作并处理转义的内置机制。

我有found a ton 的答案都使用HttpUtility。然而,这是 ASP.NET Core,不再有 System.Web 程序集,因此不再有 HttpUtility

针对核心运行时,在 ASP.NET Core 中执行此操作的适当方法是什么?

【问题讨论】:

  • Microsoft.AspNet.WebUtilties 的替代品可能是Mono.HttpUtility library
  • 2017 年更新:.NET Core 2.0 现在包括 HttpUtilityParseQueryString 方法。

标签: c# asp.net asp.net-core


【解决方案1】:

如果您使用的是 ASP.NET Core 1 或 2,则可以使用 Microsoft.AspNetCore.WebUtilities 包中的 Microsoft.AspNetCore.WebUtilities.QueryHelpers 执行此操作。

如果您使用的是 ASP.NET Core 3.0 或更高版本,WebUtilities 现在是 ASP.NET SDK 的一部分,不需要单独的 nuget 包引用。

将其解析为字典:

var uri = new Uri(context.RedirectUri);
var queryDictionary = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);

请注意,与 System.Web 中的 ParseQueryString 不同,它在 ASP.NET Core 1.x 中返回 IDictionary<string, string[]> 类型的字典,在 ASP.NET Core 2.x 或更高版本中返回 IDictionary<string, StringValues> 类型的字典,因此值是字符串的集合。这就是字典处理多个同名查询字符串参数的方式。

如果要在查询字符串上添加参数,可以在QueryHelpers上使用另一种方法:

var parametersToAdd = new System.Collections.Generic.Dictionary<string, string> { { "resource", "foo" } };
var someUrl = "http://www.google.com";
var newUri = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(someUrl, parametersToAdd);

使用 .net core 2.2 可以获取查询字符串

var request = HttpContext.Request;
var query = request.Query;
foreach (var item in query){
   Debug.WriteLine(item) 
}

你会得到一个键值对的集合——像这样

[0] {[companyName, ]}
[1] {[shop, ]}
[2] {[breath, ]}
[3] {[hand, ]}
[4] {[eye, ]}
[5] {[firstAid, ]}
[6] {[eyeCleaner, ]}

【讨论】:

  • 仅供参考,WebUtilities 包与 .net core 1.0 不兼容。你可能需要Microsoft.AspNetCore.WebUtilities
  • @Jaime 很棒的观察!您可以使用该更新编辑我的答案,以便获得荣誉吗?
  • 版已完成。为遗留 .net 版本保留旧的命名空间。
  • 返回类型现在是 IDictionary 而不是 IDictionary
  • 在 Asp.net Core 2.2 中这不起作用。 ParseQuery 返回一个 Dictionary 并且没有 AddQueryString 接受它。
【解决方案2】:

仅使用 ASP.NET Core 包获取绝对 URI 并操作其查询字符串的最简单、最直观的方法,只需几个简单的步骤即可完成:

安装包

PM> Install-Package Microsoft.AspNetCore.WebUtilities
PM> Install-Package Microsoft.AspNetCore.Http.Extensions

重要类

为了指出它们,以下是我们将使用的两个重要类:QueryHelpersStringValuesQueryBuilder

代码

// Raw URI including query string with multiple parameters
var rawurl = "https://bencull.com/some/path?key1=val1&key2=val2&key2=valdouble&key3=";

// Parse URI, and grab everything except the query string.
var uri = new Uri(rawurl);
var baseUri = uri.GetComponents(UriComponents.Scheme | UriComponents.Host | UriComponents.Port | UriComponents.Path, UriFormat.UriEscaped);

// Grab just the query string part
var query = QueryHelpers.ParseQuery(uri.Query);

// Convert the StringValues into a list of KeyValue Pairs to make it easier to manipulate
var items = query.SelectMany(x => x.Value, (col, value) => new KeyValuePair<string, string>(col.Key, value)).ToList();

// At this point you can remove items if you want
items.RemoveAll(x => x.Key == "key3"); // Remove all values for key
items.RemoveAll(x => x.Key == "key2" && x.Value == "val2"); // Remove specific value for key

// Use the QueryBuilder to add in new items in a safe way (handles multiples and empty values)
var qb = new QueryBuilder(items);
qb.Add("nonce", "testingnonce");
qb.Add("payerId", "pyr_");

// Reconstruct the original URL with new query string
var fullUri = baseUri + qb.ToQueryString();

要及时了解任何更改,您可以在此处查看我的博客文章:http://benjii.me/2017/04/parse-modify-query-strings-asp-net-core/

【讨论】:

    【解决方案3】:

    HttpRequest 有一个Query 属性,它通过IReadableStringCollection 接口公开解析的查询字符串:

    /// <summary>
    /// Gets the query value collection parsed from owin.RequestQueryString.
    /// </summary>
    /// <returns>The query value collection parsed from owin.RequestQueryString.</returns>
    public abstract IReadableStringCollection Query { get; }
    

    GitHub 上的This discussion 也指向它。

    【讨论】:

      【解决方案4】:

      此函数返回Dictionary&lt;string, string&gt; 并且不使用Microsoft.xxx 以实现兼容性

      两边都接受参数编码

      接受重复键(返回最后一个值)

      var rawurl = "https://emp.com/some/path?key1.name=a%20line%20with%3D&key2=val2&key2=valdouble&key3=&key%204=44#book1";
      var uri = new Uri(rawurl);
      Dictionary<string, string> queryString = ParseQueryString(uri.Query);
      
      // queryString return:
      // key1.name, a line with=
      // key2, valdouble
      // key3, 
      // key 4, 44
      
      public Dictionary<string, string> ParseQueryString(string requestQueryString)
      {
          Dictionary<string, string> rc = new Dictionary<string, string>();
          string[] ar1 = requestQueryString.Split(new char[] { '&', '?' });
          foreach (string row in ar1)
          {
              if (string.IsNullOrEmpty(row)) continue;
              int index = row.IndexOf('=');
              if (index < 0) continue;
              rc[Uri.UnescapeDataString(row.Substring(0, index))] = Uri.UnescapeDataString(row.Substring(index + 1)); // use Unescape only parts          
           }
           return rc;
      }
      

      【讨论】:

      • 这行得通,但你应该在开始子串之前添加索引检查,因为有可能,该行不包含'='。这会导致异常。
      • 感谢@Taurib 的帮助,已更改
      • 警告:如果查询中有数组,这将不起作用,因为字典设置为 ! (例如“?item=1&item=2”)解决方法:使用 IEnumerable> 或 Dictionary for .net core 3.1
      • 感谢@theCuriousOne,在这个例程中,为了简单起见,返回最后一个值,“接受重复键(返回最后一个值)”,您的解决方案可以返回所有值。
      【解决方案5】:

      重要的是要注意,自从最佳答案被标记为正确以来,Microsoft.AspNetCore.WebUtilities 已经进行了主要版本更新(从 1.x.x 到 2.x.x)。

      也就是说,如果您是针对 netcoreapp1.1 构建的,您将需要运行以下命令,它会安装支持的最新版本 1.1.2

      Install-Package Microsoft.AspNetCore.WebUtilities -Version 1.1.2

      【讨论】:

        【解决方案6】:

        我使用它作为扩展方法,可以使用任意数量的参数:

        public static string AddOrReplaceQueryParameter(this HttpContext c, params string[] nameValues)
            {
                if (nameValues.Length%2!=0)
                {
                    throw new Exception("nameValues: has more parameters then values or more values then parameters");
                }
                var qps = new Dictionary<string, StringValues>();
                for (int i = 0; i < nameValues.Length; i+=2)
                {
                    qps.Add(nameValues[i], nameValues[i + 1]);
                }
                return c.AddOrReplaceQueryParameters(qps);
            }
        
        public static string AddOrReplaceQueryParameters(this HttpContext c, Dictionary<string,StringValues> pvs)
            {
                var request = c.Request;
                UriBuilder uriBuilder = new UriBuilder
                {
                    Scheme = request.Scheme,
                    Host = request.Host.Host,
                    Port = request.Host.Port ?? 0,
                    Path = request.Path.ToString(),
                    Query = request.QueryString.ToString()
                };
        
                var queryParams = QueryHelpers.ParseQuery(uriBuilder.Query);
        
                foreach (var (p,v) in pvs)
                {
                    queryParams.Remove(p);
                    queryParams.Add(p, v);
                }
        
                uriBuilder.Query = "";
                var allQPs = queryParams.ToDictionary(k => k.Key, k => k.Value.ToString());
                var url = QueryHelpers.AddQueryString(uriBuilder.ToString(),allQPs);
        
                return url;
            }
        
        

        例如视图中的下一个和上一个链接:

        var next = Context.Request.HttpContext.AddOrReplaceQueryParameter("page",Model.PageIndex+1+"");
        
        var prev = Context.Request.HttpContext.AddOrReplaceQueryParameter("page",Model.PageIndex-1+"");
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-17
          • 1970-01-01
          • 2010-09-09
          • 2019-05-03
          • 2011-02-27
          相关资源
          最近更新 更多