Jeśli chcę przesłać żądanie HTTP get za pomocą System.Net.HttpClient, wydaje się, że nie ma interfejsu API do dodawania parametrów, czy to prawda?
Czy jest dostępny jakiś prosty interfejs API do zbudowania ciągu zapytania, który nie wymaga zbudowania kolekcji wartości nazw i adresu URL kodującego je, a następnie ich konkatenacji? Miałem nadzieję użyć czegoś takiego jak API RestSharp (tj. AddParameter (..))
Odpowiedzi:
Tak.
Pewnie:
da ci oczekiwany wynik:
Może się również
UriBuilder
przydać klasa:da ci oczekiwany wynik:
że możesz bardziej niż bezpiecznie karmić swoją
HttpClient.GetAsync
metodę.źródło
#
) za pomocą właściwości Fragment. Widziałem tak wielu ludzi, którzy popełniają błąd polegający na ręcznym obsługiwaniu adresów URL zamiast korzystania z wbudowanych narzędzi.NameValueCollection.ToString()
normalnie nie tworzy ciągów zapytań i nie ma dokumentacji stwierdzającej, że wykonanieToString
wynikuParseQueryString
spowoduje powstanie nowego ciągu zapytań, a zatem może zostać zerwane w dowolnym momencie, ponieważ nie ma gwarancji na tę funkcjonalność.Dla tych, którzy nie chcą zawierać
System.Web
w projektach, które nie korzystają już go można użyćFormUrlEncodedContent
odSystem.Net.Http
i zrobić coś jak poniżej:wersja keyvaluepair
wersja słownikowa
źródło
dispose
? Zawsze się pozbywam, chyba że mam dobry powód, aby tego nie robić, na przykład ponowne użycieHttpClient
.TL; DR: nie używaj zaakceptowanej wersji, ponieważ jest całkowicie zepsuta w związku z obsługą znaków Unicode i nigdy nie używaj wewnętrznego API
Znalazłem dziwny problem podwójnego kodowania z zaakceptowanym rozwiązaniem:
Jeśli więc masz do czynienia ze znakami, które muszą zostać zakodowane, zaakceptowane rozwiązanie prowadzi do podwójnego kodowania:
NameValueCollection
indeksatora ( i używa tegoUrlEncodeUnicode
, nie jest to normalnie oczekiwaneUrlEncode
(!) )uriBuilder.Uri
tworzy nowyUri
za pomocą konstruktora, który koduje jeszcze raz (normalne kodowanie adresu URL)uriBuilder.ToString()
(nawet jeśli to zwraca poprawne,Uri
która IMO jest co najmniej niespójnością, być może błędem, ale to kolejne pytanie), a następnie za pomocąHttpClient
metody akceptującej ciąg - klient nadal tworzyUri
z przekazanego ciągu w następujący sposób:new Uri(uri, UriKind.RelativeOrAbsolute)
Małe, ale pełne repro:
Wynik:
Jak widać, bez względu na to, czy zrobisz
uribuilder.ToString()
+httpClient.GetStringAsync(string)
luburiBuilder.Uri
+httpClient.GetStringAsync(Uri)
, ostatecznie wyślesz podwójnie zakodowany parametrNaprawionym przykładem może być:
Ale używa to przestarzałego
Uri
konstruktoraPS w moim najnowszym .NET na Windows Server,
Uri
konstruktor z komentarzem bool doc mówi „przestarzały, dontEscape jest zawsze fałszywy”, ale w rzeczywistości działa zgodnie z oczekiwaniami (pomija ucieczkę)Wygląda to na kolejny błąd ...
I nawet to jest po prostu źle - wysyła UrlEncodedUnicode do serwera, a nie tylko UrlEncoded, czego oczekuje serwer
Aktualizacja: jeszcze jedno: NameValueCollection faktycznie wykonuje UrlEncodeUnicode, którego nie należy już używać i jest niezgodny ze zwykłym url.encode / decode (patrz NameValueCollection do zapytania URL? ).
Więc sedno brzmi: nigdy nie używaj tego hacka,
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
ponieważ spowoduje to bałagan parametrów zapytania unicode. Wystarczy zbudować zapytanie ręcznie i przypisać je do tego,UriBuilder.Query
które wykona niezbędne kodowanie, a następnie użyje UriUriBuilder.Uri
.Doskonały przykład zranienia się za pomocą kodu, którego nie należy używać w ten sposób
źródło
var namedValues = HttpUtility.ParseQueryString(builder.Query)
, ale zamiast użycia zwróconej NameValueCollection, natychmiast przekonwertuj ją na słownik w następujący sposób:var dic = values.ToDictionary(x => x, x => values[x]);
Dodaj nowe wartości do słownika, a następnie przekaż je konstruktorowiFormUrlEncodedContent
i wywołajReadAsStringAsync().Result
. To daje poprawnie zakodowany ciąg zapytania, który możesz przypisać z powrotem do UriBuilder.<add key="aspnet:DontUsePercentUUrlEncoding" value="true" />
. Nie zależałbym od tego zachowania, więc lepiej jest użyć klasy FormUrlEncodedContent, jak wykazano we wcześniejszej odpowiedzi: stackoverflow.com/a/26744471/88409W projekcie ASP.NET Core można użyć klasy QueryHelpers.
źródło
Możesz wypróbować Flurl [ujawnienie: jestem autorem], płynnego narzędzia do tworzenia adresów URL z opcjonalną biblioteką towarzyszącą, która rozszerza go na pełnoprawnego klienta REST.
Sprawdź dokumenty, aby uzyskać więcej informacji. 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
Uri
lub zacząć od własnej klasy zamiaststring
?Url
klasy. Powyższe jest równoważnenew Url("https://api.com").AppendPathSegment...
Osobiście wolę rozszerzenia ciągów ze względu na mniejszą liczbę naciśnięć klawiszy i znormalizowane na nich w dokumentach, ale możesz to zrobić w każdy sposób.Według tych samych zasad jak słupka Rostowa, jeśli nie chcą zawierać odniesienie do
System.Web
w projekcie, można korzystaćFormDataCollection
zSystem.Net.Http.Formatting
i zrobić coś jak następuje:Za pomocą
System.Net.Http.Formatting.FormDataCollection
źródło
Darin zaoferował ciekawe i sprytne rozwiązanie, a oto coś, co może być inną opcją:
i podczas korzystania z niego możesz to zrobić:
źródło
kvp.Key
ikvp.Value
osobno wewnątrz pętli for, a nie w pełnym ciągu zapytania (tym samym nie kodując znaków&
i=
).server.UrlEncode
można je zastąpićWebUtility.UrlEncode
Lub po prostu używając mojego rozszerzenia Uri
Kod
Stosowanie
Wynik
źródło
RFC 6570 URI Template Library Zajmuję jest zdolny do wykonywania tej operacji. Wszystkie kodowania są obsługiwane zgodnie z RFC. W chwili pisania tego tekstu dostępna jest wersja beta, a jedynym powodem, dla którego nie jest uważana za stabilną wersję 1.0, jest to, że dokumentacja nie w pełni spełnia moje oczekiwania (patrz numery 17 , 18 , 32 , 43 ).
Możesz zbudować ciąg zapytania sam:
Lub możesz zbudować pełny URI:
źródło
Ponieważ muszę użyć tego czasu kilka razy, wymyśliłem tę klasę, która po prostu pomaga wyodrębnić sposób tworzenia ciągu zapytania.
Użycie zostanie uproszczone do czegoś takiego:
, który zwróci identyfikator: http://example.com/?foo=bar%3c%3e%26-baz&bar=second
źródło
Aby uniknąć problemu podwójnego kodowania opisanego w odpowiedzi na taras.roshko i zachować możliwość łatwej pracy z parametrami zapytania, możesz użyć
uriBuilder.Uri.ParseQueryString()
zamiastHttpUtility.ParseQueryString()
.źródło
Dobra część zaakceptowanej odpowiedzi, zmodyfikowana do użycia UriBuilder.Uri.ParseQueryString () zamiast HttpUtility.ParseQueryString ():
źródło
ParseQueryString()
metoda rozszerzenia nie istniejeSystem
.Dzięki „Darin Dimitrov”, To są metody rozszerzenia.
źródło
Nie mogłem znaleźć lepszego rozwiązania niż stworzenie metody rozszerzenia do konwersji słownika na QueryStringFormat. Rozwiązanie zaproponowane przez Waleed AK jest również dobre.
Postępuj zgodnie z moim rozwiązaniem:
Utwórz metodę rozszerzenia:
I oni:
źródło