Como você UrlEncode sem usar o System.Web?

310

Estou tentando escrever um aplicativo cliente do Windows que chama um site para obter dados. Para manter a instalação no mínimo, estou tentando usar apenas dlls no .NET Framework Client Profile . O problema é que eu preciso UrlEncode alguns parâmetros, existe uma maneira fácil de fazer isso sem importar o System.Web.dll, que não faz parte do perfil do cliente?

Martin Brown
fonte
Você poderia mostrar como está realizando a chamada para o site? Talvez haja algo que possa ser feito lá.
Darin Dimitrov
Por curiosidade, como você chama um site para obter dados sem usar o System.Web?
Patrick McDonald
@ Patrick, ele provavelmente está usando WebRequestou WebClient. Essa é a razão pela qual perguntei sobre esse código específico, porque há coisas que podem ser feitas sobre dados de codificação de URL corretamente.
Darin Dimitrov
1
Estou usando um objeto System.Net.WebRequest. Então eu chamo GetRequestStream e escrevo meus parâmetros Post no fluxo. Também defino o ContentType como "application / x-www-form-urlencoded".
Martin Brown
1
É claro que isso se aplicaria igualmente bem se eu estivesse executando uma solicitação GET e anexando os parâmetros ao URL.
Martin Brown

Respostas:

317

System.Uri.EscapeUriString() pode ser problemático com certos caracteres, para mim era um sinal de número / libra '#' na string.

Se esse é um problema para você, tente:

System.Uri.EscapeDataString() //Works excellent with individual values

Aqui está uma resposta da pergunta SO que explica a diferença:

Qual é a diferença entre EscapeUriString e EscapeDataString?

e recomenda usar Uri.EscapeDataString()em qualquer aspecto.

ToddBFisher
fonte
1
Falso: blogs.msdn.com/b/yangxind/archive/2006/11/09/… Você terá problemas com sinais de adição, pois eles não serão codificados.
22812 Chris Weber
7
Essa postagem do blog é um pouco antiga e eu apenas "Uri escapei" de uma URL completa e todos os espaços se tornaram% 20, então acho que eles a corrigiram. Estou usando o .Net 4.5.
Rodi
O EscapeDataString também não suporta seqüências muito longas se você estiver preparando dados para uma operação POST. stackoverflow.com/questions/6695208/…
Bron Davies
Uri.EscapeUriStringé realmente muito problemático e não deve ser usado, pois tenta fazer algo (escapando de URIs completos) que é realmente impossível de fazer de forma consistente. Consulte esta resposta para obter uma explicação detalhada.
Livven
Também um caractere '' Space.
Waqas Shabbir
252

No uso do .Net 4.5+ WebUtility

Apenas para formatação, estou enviando isso como resposta.

Não foi possível encontrar bons exemplos comparando-os assim:

string testString = "http://test# space 123/text?var=val&another=two";
Console.WriteLine("UrlEncode:         " + System.Web.HttpUtility.UrlEncode(testString));
Console.WriteLine("EscapeUriString:   " + Uri.EscapeUriString(testString));
Console.WriteLine("EscapeDataString:  " + Uri.EscapeDataString(testString));
Console.WriteLine("EscapeDataReplace: " + Uri.EscapeDataString(testString).Replace("%20", "+"));

Console.WriteLine("HtmlEncode:        " + System.Web.HttpUtility.HtmlEncode(testString));
Console.WriteLine("UrlPathEncode:     " + System.Web.HttpUtility.UrlPathEncode(testString));

//.Net 4.0+
Console.WriteLine("WebUtility.HtmlEncode: " + WebUtility.HtmlEncode(testString));
//.Net 4.5+
Console.WriteLine("WebUtility.UrlEncode:  " + WebUtility.UrlEncode(testString));

Saídas:

UrlEncode:             http%3a%2f%2ftest%23+space+123%2ftext%3fvar%3dval%26another%3dtwo
EscapeUriString:       http://test#%20space%20123/text?var=val&another=two
EscapeDataString:      http%3A%2F%2Ftest%23%20space%20123%2Ftext%3Fvar%3Dval%26another%3Dtwo
EscapeDataReplace:     http%3A%2F%2Ftest%23+space+123%2Ftext%3Fvar%3Dval%26another%3Dtwo

HtmlEncode:            http://test# space 123/text?var=val&another=two
UrlPathEncode:         http://test#%20space%20123/text?var=val&another=two

//.Net 4.0+
WebUtility.HtmlEncode: http://test# space 123/text?var=val&another=two
//.Net 4.5+
WebUtility.UrlEncode:  http%3A%2F%2Ftest%23+space+123%2Ftext%3Fvar%3Dval%26another%3Dtwo

No uso do .Net 4.5+ WebUtility.UrlEncode

Isso parece replicar HttpUtility.UrlEncode(pré-v4.0) para os caracteres mais comuns:
Uri.EscapeDataString(testString).Replace("%20", "+").Replace("'", "%27").Replace("~", "%7E")
Nota: EscapeUriStringmanterá uma string uri válida, o que fará com que use o máximo de caracteres de texto sem formatação possível.

Consulte esta resposta para obter uma tabela comparando as várias codificações:
https://stackoverflow.com/a/11236038/555798

Quebras de linha Todos eles listados aqui (exceto HttpUtility.HtmlEncode) serão convertidos "\n\r"em %0a%0dou%0A%0D

Sinta-se à vontade para editar isso e adicionar novos caracteres à minha string de teste, ou deixe-os nos comentários e eu os editarei.

Timina
fonte
No meu caso eu tive que usar EscapeDataString, em vez de EscapeUriStringcomo fomos codificação retornos de carro e alimentações de linha e estes exigido o mais agressivo escapando realizada porEscapeDataString
David O'Meara
1
mais exemplos, você pode fornecer seus próprios casos de teste, se desejar. Aqui está um exemplo de como executá-lo e os outros métodos de codificação que mostram diferenças dotnetfiddle.net/12IFw1
Maslow
3
WebUtility.UrlEncode () e WebUtility.UrlDecode () são 4.5+. Eles não existem no 4.0.
Derek Kalweit
O msdn diz: "Plataforma Universal do Windows: disponível desde a versão 4.5, .NET Framework: disponível desde a versão 4.0" ...
Thymine
54

Você pode usar

Uri.EscapeUriString (consulte http://msdn.microsoft.com/en-us/library/system.uri.escapeuristring.aspx )

Matthew Manela
fonte
Existe uma diferença entre isso e EscapeDataString?
Martin Brown
3
Você deseja usar o EscapeUriString. O EscapeUriString vai tentar codificar toda a url (incluir http: // parte), enquanto EscapeUriString entende que partes realmente deve ser codificado
Matthew Manela
1
Entendo, então, neste caso, eu provavelmente desejaria EscapeDataString, pois posso passar uma URL como parâmetro get. Estou anexando a um URL nesta instância.
Martin Brown
5
@MatthewManela eu tenho certeza que o seu comentário OCT1 deve ler O EscapeDataString vai tentar codificar ...
Maslow
Não use Uri.EscapeUriString. Ele não "entende" quais partes devem ser codificadas, é apenas uma tentativa equivocada de fazer algo (escapando dos URIs completos) que é realmente impossível fazer de forma consistente. Veja esta resposta para uma explicação detalhada.
Livven
20

As respostas aqui são muito boas, mas ainda insuficientes para mim.

Eu escrevi um pequeno laço que compara Uri.EscapeUriStringcom Uri.EscapeDataStringpara todos os caracteres de 0 a 255.

NOTA: Ambas as funções possuem a inteligência incorporada de que caracteres acima de 0x80 são codificados primeiro em UTF-8 e depois codificados em porcentagem.

Aqui está o resultado:

******* Different *******

'#' -> Uri "#" Data "%23"
'$' -> Uri "$" Data "%24"
'&' -> Uri "&" Data "%26"
'+' -> Uri "+" Data "%2B"
',' -> Uri "," Data "%2C"
'/' -> Uri "/" Data "%2F"
':' -> Uri ":" Data "%3A"
';' -> Uri ";" Data "%3B"
'=' -> Uri "=" Data "%3D"
'?' -> Uri "?" Data "%3F"
'@' -> Uri "@" Data "%40"


******* Not escaped *******

'!' -> Uri "!" Data "!"
''' -> Uri "'" Data "'"
'(' -> Uri "(" Data "("
')' -> Uri ")" Data ")"
'*' -> Uri "*" Data "*"
'-' -> Uri "-" Data "-"
'.' -> Uri "." Data "."
'_' -> Uri "_" Data "_"
'~' -> Uri "~" Data "~"

'0' -> Uri "0" Data "0"
.....
'9' -> Uri "9" Data "9"

'A' -> Uri "A" Data "A"
......
'Z' -> Uri "Z" Data "Z"

'a' -> Uri "a" Data "a"
.....
'z' -> Uri "z" Data "z"

******* UTF 8 *******

.....
'Ò' -> Uri "%C3%92" Data "%C3%92"
'Ó' -> Uri "%C3%93" Data "%C3%93"
'Ô' -> Uri "%C3%94" Data "%C3%94"
'Õ' -> Uri "%C3%95" Data "%C3%95"
'Ö' -> Uri "%C3%96" Data "%C3%96"
.....

EscapeUriStringdeve ser usado para codificar URLs, enquanto EscapeDataStringdeve ser usado para codificar, por exemplo, o conteúdo de um Cookie, porque os dados do Cookie não devem conter os caracteres '='e ';'.

Elmue
fonte
boa análise e análise aqui, muito útil. se alguém tem ou sabe de benchmarks de desempenho (comparando todos os três métodos), que também seria bom ver
Shaun Wilson
Essa é uma boa análise e o que você deve levar em consideração é que você não deve usá-lo Uri.EscapeUriString, porque é impossível fazer escape de URIs completos de forma consistente. Veja esta resposta para uma explicação detalhada.
Livven
16

Há uma versão utilizável do perfil do cliente, classe System.Net.WebUtility, presente no perfil do cliente System.dll. Aqui está o link do MSDN:

WebUtility

Sprague
fonte
Gostaria de observar que a página de ajuda para essa classe diz especificamente "Fornece métodos para codificar e decodificar URLs ao processar solicitações da Web". então pode ser que eles não tenham nomeado bem os métodos.
James White
Bom ponto, digamos, por que você não vota em um irmão;) esse voto negativo me assombra há 2 anos! JK ... mas sinceramente isso é provavelmente por isso que eu postei o link, lamentável que eu tomar uma batida reputação de erros em documentos da Microsoft ...
Sprague
11
Parece que UrlEncode e UrlDecode foram adicionados apenas ao WebUtility na versão 4.5 do .Net.
Martin Brown
8

Aqui está um exemplo de envio de uma solicitação POST que codifica corretamente os parâmetros usando o application/x-www-form-urlencodedtipo de conteúdo:

using (var client = new WebClient())
{
    var values = new NameValueCollection
    {
        { "param1", "value1" },
        { "param2", "value2" },
    };
    var result = client.UploadValues("http://foo.com", values);
}
Darin Dimitrov
fonte
-3
System.Net.WebUtility.HtmlDecode
user3105093
fonte
A classe WebUtility fornece métodos para codificar e decodificar URLs ao processar solicitações da Web. Ele faz a mesma coisa que HttpUtility mas é fora do namespace System.Web
Alexandru Aliu
3
Está errado porque HtmlDecodes e não UrlEncode como a pergunta. Mesmo HtmlEncode estaria errado, pois a codificação HTML é diferente da codificação de URL.
Martin Brown