.NET Core'da bir sorgu dizesini ayrıştırın ve değiştirin


113

Bir sorgu dizesi içeren mutlak bir URI veriliyor. Sorgu dizesine güvenle bir değer eklemek ve mevcut bir parametreyi değiştirmek istiyorum.

&foo=barDüzenli ifadeler kullanmamayı ya da tutmamayı tercih ederim , URI kaçması ustalık isteyen bir iştir. Bunun yerine, bunu doğru bir şekilde yapacağını ve kaçışla başa çıkacağını bildiğim yerleşik bir mekanizma kullanmak istiyorum.

Ben ettik bulundu bir ton tüm kullanım olduğunu cevapların HttpUtility. Ancak bu ASP.NET Core olduğundan, artık System.Web derlemesi yoktur, dolayısıyla artık yoktur HttpUtility.

Çekirdek çalışma zamanını hedeflerken ASP.NET Core'da bunu yapmanın uygun yolu nedir?


Kitaplığa bir alternatif Microsoft.AspNet.WebUtiltiesolabilir . Mono.HttpUtility
mason


2
Güncelleme 2017: .NET Core 2.0 artık içerir HttpUtilityve ParseQueryStringyöntemi.
KTCO

Yanıtlar:


152

Eğer ASP.NET Çekirdek 1 veya 2 kullanıyorsanız, sen ile yapabilirsiniz Microsoft.AspNetCore.WebUtilities.QueryHelpersiçinde Microsoft.AspNetCore.WebUtilities paketinde.

ASP.NET Core 3.0 veya WebUtilitiesüstünü kullanıyorsanız , artık ASP.NET SDK'nın bir parçasıdır ve ayrı bir nuget paketi başvurusu gerektirmez.

Bir sözlüğe ayrıştırmak için:

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

ParseQueryStringSystem.Web'den farklı olarak, bunun IDictionary<string, string[]>ASP.NET Core 1.x veya IDictionary<string, StringValues>ASP.NET Core 2.x veya daha büyük sürümlerde bir tür sözlüğü döndürdüğünü unutmayın , bu nedenle değer bir dizeler koleksiyonudur. Sözlük, aynı ada sahip birden çok sorgu dizesi parametresini bu şekilde işler.

Sorgu dizesine bir parametre eklemek istiyorsanız, şurada başka bir yöntem kullanabilirsiniz 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'yi kullanarak sorgu dizesini şu şekilde alabilirsiniz:

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

Anahtar: değer çiftlerinden oluşan bir koleksiyon elde edeceksiniz - bunun gibi

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

1
Bilginize, WebUtilities paketi .net core 1.0 ile uyumlu değildir. Bunun Microsoft.AspNetCore.WebUtilitiesyerine ihtiyacınız olabilir .
Jaime

6
@Jaime Harika gözlem! Cevabımı bu güncellemeyle düzenleyebilir misiniz, böylece kredi alırsınız?
vcsjones

3
Baskı tamamlandı. Eski .net sürümleri için de eski ad alanı korunur.
Jaime

1
Görünüşe göre QueryHelpers.AddQueryString, dizeleri otomatik olarak UrlEscape yapacaktır - kullanışlı.
Josh

2
Dönüş türü artık IDictionary <string, string []> yerine IDictionary <string,
StringValues

35

Mutlak bir URI almanın ve sorgu dizesini yalnızca ASP.NET Core paketlerini kullanarak değiştirmenin en kolay ve en sezgisel yolu, birkaç kolay adımda yapılabilir:

Paketleri Yükleyin

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

Önemli Sınıflar

Bunları belirtmek için kullanacağımız iki önemli sınıf şunlardır: QueryHelpers , StringValues , QueryBuilder .

Kod

// 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();

Değişikliklerden haberdar olmak için, bu konudaki blog yazıma buradan bakabilirsiniz: http://benjii.me/2017/04/parse-modify-query-strings-asp-net-core/


17

HttpRequestQueryayrıştırılmış sorgu dizesini IReadableStringCollectionarabirim aracılığıyla ortaya çıkaran bir özelliğe sahiptir :

/// <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'daki bu tartışma da buna işaret ediyor.


10

Bu işlev geri döner Dictionary<string, string>ve Microsoft.xxxuyumluluk için kullanmaz

Her iki tarafta parametre kodlamasını kabul eder

Yinelenen anahtarları kabul eder (son değeri döndürür)

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;
}

Bu çalışır, ancak alt dizeye başlamadan önce dizin kontrolü eklemelisiniz, çünkü bu satırda '=' bulunmaz. Hangi istisnaya neden olur.
Taurib

1
Yardım için teşekkürler @Taurib, değişti
Wagner Pereira

1
Uyarı: Sözlük <dizge, dizge> olarak ayarlandığından sorguda diziler varsa bu çalışmaz! (örneğin "? item = 1 & item = 2") Çözüm: .net core 3.1 için IEnumerable <KeyValuePair <string, string >> veya Dictionary <string, StringValues> kullanın
theCuriousOne

Teşekkürler @theCuriousOne, bu rutinde, basitlik için son değeri, "Yinelenen anahtarları kabul eder (son değeri döndür)" döndürür, çözümünüz tüm değerleri döndürmek için uygundur.
Wagner Pereira

1

En üstteki yanıtın doğru olarak işaretlenmesinden bu Microsoft.AspNetCore.WebUtilitiesyana, büyük bir sürüm güncellemesi (1.xx'den 2.xx'e) yapıldığına dikkat etmek önemlidir.

Bununla birlikte, aleyhinize inşa netcoreapp1.1ediyorsanız, desteklenen en son sürümü yükleyen aşağıdakileri çalıştırmanız gerekecektir 1.1.2:

Install-Package Microsoft.AspNetCore.WebUtilities -Version 1.1.2


1

Bunu genişletme yöntemi olarak kullanıyorum, herhangi bir sayıda parametre ile çalışıyor:

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;
    }

Sonraki ve önceki bağlantılar, örneğin bir görünümde:

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

var prev = Context.Request.HttpContext.AddOrReplaceQueryParameter("page",Model.PageIndex-1+"");
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.