Typowym zadaniem podczas wywoływania zasobów sieciowych z kodu jest budowanie ciągu zapytania zawierającego wszystkie niezbędne parametry. Chociaż z całą pewnością nie ma wiedzy o rakietach, jest kilka fajnych szczegółów, o które trzeba dbać, dodając &
pierwszy parametr, jeśli nie pierwszy, kodując parametry itp.
Kod do zrobienia tego jest bardzo prosty, ale nieco żmudny:
StringBuilder SB = new StringBuilder();
if (NeedsToAddParameter A)
{
SB.Append("A="); SB.Append(HttpUtility.UrlEncode("TheValueOfA"));
}
if (NeedsToAddParameter B)
{
if (SB.Length>0) SB.Append("&");
SB.Append("B="); SB.Append(HttpUtility.UrlEncode("TheValueOfB")); }
}
Jest to tak powszechne zadanie, jakiego można oczekiwać od klasy użytkowej, która czyni ją bardziej elegancką i czytelną. Podczas skanowania MSDN nie udało mi się go znaleźć - co prowadzi mnie do następującego pytania:
Jaki jest najbardziej elegancki i czysty sposób wykonywania powyższych czynności?
c#
.net
url
query-string
Boaz
źródło
źródło
Odpowiedzi:
Jeśli spojrzysz pod maską, właściwość QueryString to NameValueCollection. Kiedy robiłem podobne rzeczy, zwykle byłem zainteresowany serializacją ORAZ deserializacją, więc moją sugestią jest zbudowanie NameValueCollection w górę, a następnie przejście do:
Wyobrażam sobie, że jest też bardzo elegancki sposób na zrobienie tego w LINQ ...
źródło
application/x-www-form-urlencoded
i jest faktycznie zdefiniowany przez HTML, w celu przesłania danych formularza w ramachGET
żądania. HTML 5 nie zabrania wielu wartości na klucz w tym formacie i w rzeczywistości wymaga, aby przeglądarka wygenerowała wiele wartości na klucz w przypadku, gdy strona (niepoprawnie) zawiera wiele pól o tym samymname
atrybucie. Zobacz goo.gl/uk1AgMożesz utworzyć nową instancję do zapisu
HttpValueCollection
, dzwoniącSystem.Web.HttpUtility.ParseQueryString(string.Empty)
, a następnie użyć jej jako dowolnejNameValueCollection
. Po dodaniu żądanych wartości możesz wywołaćToString
kolekcję, aby uzyskać ciąg zapytania, w następujący sposób:HttpValueCollection
Jest wewnętrzna i nie można więc bezpośrednio skonstruowania instancji. Jednak po uzyskaniu instancji możesz używać jej tak samo, jak każdej innejNameValueCollection
. Ponieważ rzeczywistym obiektem, z którym pracujesz, jestHttpValueCollection
wywołanie metody ToString wywoła metodę przesłoniętąHttpValueCollection
, która formatuje kolekcję jako ciąg zapytania zakodowany w adresie URL.Po przeszukaniu SO i Internetu w poszukiwaniu odpowiedzi na podobny problem jest to najprostsze rozwiązanie, jakie udało mi się znaleźć.
.NET Core
Jeśli pracujesz w .NET Core, możesz użyć
Microsoft.AspNetCore.WebUtilities.QueryHelpers
klasy, co znacznie to upraszcza.https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers
Przykładowy kod:
źródło
public static string ToURLQueryString(this IDictionary dict) { ... }
Add
metody. Tj.queryString.Add("type", "1"); queryString.Add("type", "2");
Stosowanie tejAdd
metody jest prawdopodobnie lepszym sposobem na robienie tego przez cały czas.Inspirując się komentarzem Roya Tinkera, skończyłem na prostej metodzie rozszerzenia klasy Uri, dzięki czemu mój kod jest zwięzły i czysty:
Stosowanie:
Edycja - wariant zgodny ze standardami
Jak zauważyło kilka osób,
httpValueCollection.ToString()
koduje znaki Unicode w sposób niezgodny ze standardami . Jest to wariant tej samej metody rozszerzenia, która obsługuje takie znaki, wywołującHttpUtility.UrlEncode
metodę zamiast przestarzałejHttpUtility.UrlEncodeUnicode
metody.źródło
Jakiś czas temu odpowiedziałem na podobne pytanie . Zasadniczo najlepszym sposobem byłoby użycie klasy
HttpValueCollection
, którąRequest.QueryString
faktycznie jest właściwość ASP.NET , niestety jest ona wewnętrzna w środowisku .NET. Możesz użyć Odbłyśnika, aby go złapać (i umieścić w swojej klasie Utils). W ten sposób możesz manipulować ciągiem zapytania jak NameValueCollection, ale przy wszystkich problemach związanych z kodowaniem / dekodowaniem adresów URL.HttpValueCollection
rozszerzaNameValueCollection
i ma konstruktor, który pobiera zakodowany ciąg zapytania (w tym znaki handlowe i znaki zapytania), i zastępujeToString()
metodę późniejszej odbudowy ciągu zapytania z podstawowej kolekcji.Przykład:
źródło
httpValueCollection.ToString()
faktycznie wywołuje,httpValueCollection.ToString(true)
więc dodanietrue
jawności nie jest wymagane.Oto płynny / lambda-ish sposób jako metoda rozszerzenia (łączenie pojęć z poprzednich postów), który obsługuje wiele wartości dla tego samego klucza. Osobiście wolę rozszerzenia niż opakowania, aby inni członkowie zespołu mogli odkryć takie rzeczy. Zwróć uwagę, że istnieją metody kontrowersji dotyczące metod kodowania, mnóstwo postów na ten temat na Stack Overflow (jeden taki post ) i blogerów MSDN (takich jak ten ).
edycja: z obsługą zerową, chociaż prawdopodobnie będziesz musiał dostosować go do konkretnej sytuacji
źródło
Flurl [ujawnienie: jestem autorem] obsługuje budowanie ciągów zapytań za pomocą anonimowych obiektów (między innymi):
Opcjonalna biblioteka towarzysząca Flurl.Http umożliwia wykonywanie połączeń HTTP bezpośrednio z tego samego płynnego łańcucha połączeń, rozszerzając go na pełnoprawnego klienta REST:
Pełny pakiet jest dostępny na NuGet:
PM> Install-Package Flurl.Http
lub po prostu samodzielny program do tworzenia adresów URL:
PM> Install-Package Flurl
źródło
Oto mój późny wpis. Nie lubiłem żadnego z innych z różnych powodów, więc napisałem własny.
Ta wersja zawiera:
Używanie tylko StringBuilder. Brak wywołań ToArray () lub innych metod rozszerzenia. Nie wygląda tak ładnie, jak niektóre inne odpowiedzi, ale uważam to za podstawową funkcję, więc wydajność jest ważniejsza niż posiadanie „płynnego”, „jednowierszowego” kodu, który ukrywa nieefektywność.
Obsługuje wiele wartości na klucz. (Sam tego nie potrzebowałem, tylko po to, żeby uciszyć Mauricio;)
Przykładowe użycie
Wynik
źródło
Co powiesz na tworzenie metod rozszerzeń, które pozwalają dodawać parametry w płynnym stylu, takim jak ten?
Oto przeciążenie, które wykorzystuje
string
:A oto przeciążenie, które wykorzystuje
StringBuilder
:źródło
NameValueCollection
,HttpValueCollection
alboUri
pierwszy. Dzięki!Musiałem rozwiązać ten sam problem dla przenośnej biblioteki klas (PCL), nad którą pracuję. W takim przypadku nie mam dostępu do System.Web, więc nie mogę używać ParseQueryString.
Zamiast tego użyłem
System.Net.Http.FormUrlEncodedContent
tak:źródło
źródło
.ToArray()
s.Dodaj tę klasę do swojego projektu
I użyj tego w ten sposób:
źródło
Moja propozycja:
Stosowanie:
źródło
Nie przetestowano, ale myślę, że coś w tym stylu działałoby całkiem nieźle
źródło
Wersja oparta na metodzie szybkiego rozszerzenia:
Możesz użyć klauzuli where, aby wybrać parametry, które zostaną dodane do ciągu.
źródło
Zakładając, że chcesz zmniejszyć zależności do innych zespołów i uprościć sprawę, możesz:
Działa to również dobrze z pętlami. Ostateczne usunięcie ampersand musi wyjść poza pętlę.
Należy zauważyć, że operator konkatenacji służy do poprawy czytelności. Koszt korzystania z niego w porównaniu z kosztem korzystania z StringBuilder jest minimalny (myślę, że Jeff Atwood opublikował coś na ten temat).
źródło
W połączeniu najlepsze odpowiedzi, aby utworzyć anonimową wersję obiektu :
To generuje:
Oto kod:
źródło
Taki sam jak przyjęte rozwiązanie, ale przeniesiony do składni LINQ „kropka” ...
źródło
Mam metodę rozszerzenia dla Uri, która:
uri.WithQuery(new { name = "value" })
string/string
par (np. Dictionary`2 ).string/object
par (np. RouteValueDictionary ).Udokumentowaną wersję można znaleźć tutaj .
Rozszerzenie:
Analizator składni zapytań:
Oto testy:
źródło
Klasa opakowującego łańcucha dla HttpValueCollection:
Przykładowe użycie:
źródło
Dodałem następującą metodę do mojej klasy PageBase.
Zadzwonić:
źródło
Napisałem kilka metod rozszerzenia, które okazały się bardzo przydatne podczas pracy z QueryStrings. Często chcę zacząć od bieżącego QueryString i zmodyfikować przed użyciem. Coś jak,
Więcej i źródło: http://www.charlesrcook.com/archive/2008/07/23/c-extension-methods-for-asp.net-query-string-operations.aspx
To podstawowe, ale podoba mi się styl.
źródło
Chciałem tylko wrzucić moje 2 centy:
Dokumenty mówią, że
uri.Query
zacznie się od?
jeśli nie jest pusty i powinieneś go przyciąć, jeśli chcesz go zmodyfikować.Uwaga, która
HttpUtility.UrlEncode
znajduje się wSystem.Web
.Stosowanie:
źródło
Chociaż nie jest elegancki, zdecydowałem się na prostszą wersję, która nie używa
NameValueCollecitons
- po prostu owinięty wzór konstruktoraStringBuilder
.Przy istniejących odpowiedziach upewniłem się, że korzystam z
HttpUtility.UrlEncode
połączeń. Używa się go tak:źródło
Wynik:
Kod; wszyscy możecie gdzieś podziękować: D
źródło
Poszedłem z rozwiązaniem zaproponowanym przez DSO (odpowiedź 2 sierpnia 11 o 7:29), jego rozwiązanie nie wymaga użycia HttpUtility. Jednak zgodnie z artykułem opublikowanym w Dotnetpearls korzystanie ze słownika jest szybsze (pod względem wydajności) niż korzystanie z NameValueCollection. Oto rozwiązanie DSO zmodyfikowane do używania Dictionary zamiast NameValueCollection.
źródło
Ciąg zapytania można dodać do adresu URL poprzez:
https://blog.codingnovice.com/blog
źródło
Napisałem pomocnika do mojego projektu maszynki do golenia, korzystając z niektórych wskazówek z innych odpowiedzi.
Firma ParseQueryString jest konieczna, ponieważ nie wolno nam manipulować obiektem QueryString bieżącego żądania.
Używam tego w ten sposób:
Jeśli chcesz, aby przyjmował więcej niż jedną wartość, po prostu zmień parametry na Słownik i dodaj pary do ciągu zapytania.
źródło
Poniższy kod jest usuwany z
HttpValueCollection
implementacji zaToString
pośrednictwem ILSpy, co daje kwerendę nazwa = wartość.Niestety HttpValueCollection jest klasą wewnętrzną, którą możesz odzyskać tylko wtedy, gdy używasz
HttpUtility.ParseQueryString()
. Usunąłem wszystkie części viewstate i domyślnie koduje:źródło
Jest to identyczna z przyjętą odpowiedzią, z wyjątkiem nieco bardziej zwartej:
źródło
Tylko dla tych, którzy potrzebują najpopularniejszej wersji VB.NET:
A wersja bez LINQ:
I wersja C # bez LINQ:
źródło