Si deseo enviar una solicitud de obtención de http utilizando System.Net.HttpClient parece que no hay una API para agregar parámetros, ¿es esto correcto?
¿Hay alguna api simple disponible para construir la cadena de consulta que no implique construir una colección de valores de nombre y url que los codifique y luego finalmente los concatene? Esperaba usar algo como la api de RestSharp (es decir, AddParameter (..))
Respuestas:
Si.
Por supuesto:
te dará el resultado esperado:
También puede encontrar
UriBuilder
útil la clase:te dará el resultado esperado:
que podría alimentar con más seguridad su
HttpClient.GetAsync
método.fuente
#
) para usted usando la propiedad Fragment. He visto a muchas personas cometer el error de manejar manualmente las URL en lugar de usar las herramientas integradas.NameValueCollection.ToString()
normalmente no realiza cadenas de consulta, y no hay documentación que indique que hacer unToString
resultadoParseQueryString
dará como resultado una nueva cadena de consulta, por lo que podría romperse en cualquier momento ya que no hay garantía en esa funcionalidad.Para aquellos que no quieren incluir
System.Web
en los proyectos que aún no lo utilizan, se puede utilizarFormUrlEncodedContent
desdeSystem.Net.Http
y hacer algo como lo siguiente:versión keyvaluepair
versión del diccionario
fuente
dispose
? Siempre dispongo a menos que tenga una buena razón para no hacerlo, como reutilizarHttpClient
.TL; DR: no use la versión aceptada ya que está completamente rota en relación con el manejo de caracteres Unicode, y nunca use API interna
De hecho, he encontrado un extraño problema de doble codificación con la solución aceptada:
Entonces, si se trata de caracteres que necesitan ser codificados, la solución aceptada conduce a una doble codificación:
NameValueCollection
indexador ( y esto utilizaUrlEncodeUnicode
, no se espera regularmenteUrlEncode
(!) )uriBuilder.Uri
, crea un nuevoUri
constructor usando que codifica una vez más (codificación de URL normal)uriBuilder.ToString()
(a pesar de que esto devuelve correctoUri
qué IMO es al menos inconsistencia, tal vez un error, pero esa es otra pregunta) y luego usando elHttpClient
método de aceptación de cadena: el cliente aún crea aUri
partir de su cadena pasada de esta manera:new Uri(uri, UriKind.RelativeOrAbsolute)
Pequeño pero completo repro:
Salida:
Como puede ver, no importa si hace
uribuilder.ToString()
+httpClient.GetStringAsync(string)
ouriBuilder.Uri
+httpClient.GetStringAsync(Uri)
, termina enviando un parámetro codificado dobleEjemplo fijo podría ser:
Pero esto usa un constructor obsoleto
Uri
PS en mi último .NET en Windows Server, el
Uri
constructor con el comentario de bool doc dice "obsoleto, dontEscape siempre es falso", pero en realidad funciona como se espera (se escapa)Entonces parece otro error ...
E incluso esto es simplemente incorrecto: envía UrlEncodedUnicode al servidor, no solo UrlEncoded lo que el servidor espera
Actualización: una cosa más es que NameValueCollection realmente hace UrlEncodeUnicode, que se supone que ya no se debe usar y es incompatible con url.encode / decode (¿Ver NameValueCollection to URL Query? ).
Entonces, la conclusión es: nunca use este truco,
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
ya que alterará sus parámetros de consulta Unicode. Simplemente construya la consulta manualmente y asígnele loUriBuilder.Query
que hará la codificación necesaria y luego use UriUriBuilder.Uri
.Primer ejemplo de lastimarse a sí mismo usando un código que no se debe usar de esta manera
fuente
var namedValues = HttpUtility.ParseQueryString(builder.Query)
, pero luego, en lugar de usar el NameValueCollection devuelto, inmediatamente conviértalo en un diccionario de la siguiente manera:var dic = values.ToDictionary(x => x, x => values[x]);
agregue nuevos valores al diccionario, luego páselo al constructor deFormUrlEncodedContent
y solicíteloReadAsStringAsync().Result
. Eso le proporciona una cadena de consulta codificada correctamente, que puede asignar de nuevo al UriBuilder.<add key="aspnet:DontUsePercentUUrlEncoding" value="true" />
. No dependería de este comportamiento, por lo que es mejor usar la clase FormUrlEncodedContent, como lo demostró una respuesta anterior: stackoverflow.com/a/26744471/88409En un proyecto ASP.NET Core puede usar la clase QueryHelpers.
fuente
Es posible que desee consultar Flurl [divulgación: soy el autor], un creador de URL fluido con lib complementario opcional que lo extiende en un cliente REST completo.
Echa un vistazo a los documentos para más detalles. El paquete completo está disponible en NuGet:
PM> Install-Package Flurl.Http
o solo el creador de URL independiente:
PM> Install-Package Flurl
fuente
Uri
o comenzar con su propia clase en lugar destring
?Url
clase. Lo anterior es equivalente anew Url("https://api.com").AppendPathSegment...
Personalmente. Prefiero las extensiones de cadena debido a menos pulsaciones de teclas y estandarizadas en los documentos, pero puede hacerlo de cualquier manera.A lo largo de las mismas líneas que el post de Rostov, si no se desea incluir una referencia a
System.Web
su proyecto, puede utilizarFormDataCollection
desdeSystem.Net.Http.Formatting
y hacer algo como lo siguiente:Utilizando
System.Net.Http.Formatting.FormDataCollection
fuente
Darin ofreció una solución interesante e inteligente, y aquí hay algo que puede ser otra opción:
y así, al usarlo, puede hacer esto:
fuente
kvp.Key
y porkvp.Value
separado dentro del bucle for, no en la cadena de consulta completa (por lo tanto, no codifica los caracteres&
y=
).server.UrlEncode
se puede reemplazar conWebUtility.UrlEncode
O simplemente usando mi extensión Uri
Código
Uso
Resultado
fuente
La biblioteca de plantillas RFC 6570 URI que estoy desarrollando es capaz de realizar esta operación. Toda la codificación se maneja para usted de acuerdo con ese RFC. En el momento de escribir este artículo, hay disponible una versión beta y la única razón por la que no se considera una versión 1.0 estable es que la documentación no cumple completamente mis expectativas (consulte los problemas # 17 , # 18 , # 32 , # 43 ).
Puede construir una cadena de consulta solo:
O podrías construir un URI completo:
fuente
Dado que tengo que reutilizar estas pocas veces, se me ocurrió esta clase que simplemente ayuda a abstraer cómo se compone la cadena de consulta.
El uso se simplificará a algo como esto:
eso devolverá la uri: http://example.com/?foo=bar%3c%3e%26-baz&bar=second
fuente
Para evitar el problema de doble codificación descrito en la respuesta de taras.roshko y mantener la posibilidad de trabajar fácilmente con parámetros de consulta, puede usar en
uriBuilder.Uri.ParseQueryString()
lugar deHttpUtility.ParseQueryString()
.fuente
Buena parte de la respuesta aceptada, modificada para usar UriBuilder.Uri.ParseQueryString () en lugar de HttpUtility.ParseQueryString ():
fuente
ParseQueryString()
método de extensión no está dentroSystem
.Gracias a "Darin Dimitrov", este es el método de extensión.
fuente
No pude encontrar una mejor solución que crear un método de extensión para convertir un Diccionario a QueryStringFormat. La solución propuesta por Waleed AK también es buena.
Sigue mi solución:
Crea el método de extensión:
Y ellos:
fuente