UriBuilder(). Запрос ошибочно кодирует символы, отличные от ASCII
Я работаю над веб-приложением asp.net mvc 4. и я использую .net 4.5. теперь у меня есть следующий класс WebClient()
:
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
query["model"] = Model;
//code goes here for other parameters....
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
var url = new UriBuilder(apiurl);
url.Query = query.ToString();
string xml = client.DownloadString(url.ToString());
XmlDocument doc = new XmlDocument();
//code goes here ....
}
теперь я заметил проблему, когда один из параметров содержит фрахтователей не ASCII, таких как £
, ¬
и т.д.
теперь окончательный запрос будет иметь любые не-ASCII символы (например, £
), закодированные неправильно (как %u00a3
). я читал об этой проблеме и, кажется, могу заменить: -
url.Query = query.ToString();
с
url.Query = ri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));
теперь с использованием более позднего подхода будет кодировать £
как %C2%A3
, который является правильным кодированным значением.
но проблема я сталкивается с url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));
, в этом случае один из параметров содержит &
, тогда url будет иметь следующий формат &operation=AddAsset&assetName=&....
, поэтому он будет считать, что я пропускаю пустой параметр propertyName not value = &
??
ИЗМЕНИТЬ
Позвольте мне снова подвести итог моей проблеме. Я хочу иметь возможность передавать следующие 3 вещи внутри моего URL-адреса в API третьей части:
-
Стандартные символы, такие как A, B, a, b, 1, 2, 3...
-
Не-ASCII-символы, такие как £
, ¬
.
-
а также специальные символы, которые используются в кодировке url, например &
, +
.
теперь я попробовал следующие 2 подхода:
Подход A:
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
query["model"] = Model;
//code goes here for other parameters....
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
var url = new UriBuilder(apiurl);
url.Query = query.ToString();
string xml = client.DownloadString(url.ToString());
XmlDocument doc = new XmlDocument();
//code goes here ....
}
В этом подходе я могу передавать такие значения, как &
, +
, поскольку они будут кодироваться по URL-адресу, но если я хочу передать не-ASCII-символы, они будут закодированы с использованием ISO-8859-1... поэтому, если у меня есть значение £
, мой код будет закодирован как %u00a3
, и он будет сохранен внутри стороннего API как %u00a3
вместо £
.
Подход B:
Я использую:
url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));
вместо
url.Query = query.ToString();
теперь я могу передавать не-ASCII-символы, такие как £
, поскольку они будут правильно закодированы с использованием UTF8 вместо ISO-8859-1. но я не могу передавать такие значения, как &
, потому что мой url будет неправильно прочитан сторонним API. Например, если я хочу передать assetName=&
, мой url будет выглядеть следующим образом:
&operation=Add&assetName=&
поэтому API-интерфейс третьей части будет считать, что я пропускаю пустой assetName
, в то время как я пытаюсь передать его значение как &...
поэтому не уверен, как я могу передать оба символа без символов ASCII + символы, такие как &
, +
????
Ответы
Ответ 1
Вместо этого вы можете использовать System.Net.Http.FormUrlEncodedContent
.
Это работает с словарем для спаривания Name/Value, а Dictionary, в отличие от NameValueCollection
, не "неправильно" отображает символы, такие как £
, на бесполезное экранирование (%u00a3
в вашем случае).
Вместо этого FormUrlEncodedContent
может принимать словарь в своем конструкторе. Когда вы прочитаете строку из нее, она будет правильно присвоена значения словаря.
Он будет правильно и равномерно обрабатывать оба случая, с которыми вы столкнулись:
-
£
(который превышает диапазон значений символов urlencoding и должен быть закодирован в шестнадцатеричное значение для транспортировки)
-
&
(который, как вы говорите, имеет значение в URL-адресе в качестве разделителя параметров, так что значения не могут содержать его - так что он также должен быть закодирован).
Здесь приведен пример кода, который показывает, что различные типы элементов примера, которые вы упомянули (представленные item1, item2 и item3), теперь правильно вернулись в urlencoded:
String item1 = "£";
String item2 = "&";
String item3 = "xyz";
Dictionary<string,string> queryDictionary = new Dictionary<string, string>()
{
{"item1", item1},
{"item2", item2},
{"item3", item3}
};
var queryString = new System.Net.Http.FormUrlEncodedContent(queryDictionary)
.ReadAsStringAsync().Result;
queryString
будет содержать item1=%C2%A3&item2=%26&item3=xyz
.
Ответ 2
Возможно, вы можете попробовать использовать Extension method
в классе NameValueCollection
. Что-то вроде этого:
using System.Collections.Specialized;
using System.Text;
using System.Web;
namespace Testing
{
public static class NameValueCollectionExtension
{
public static string ToUtf8UrlEncodedQuery(this NameValueCollection nv)
{
StringBuilder sb = new StringBuilder();
bool firstIteration = true;
foreach (var key in nv.AllKeys)
{
if (!firstIteration)
sb.Append("&");
sb.Append(HttpUtility.UrlEncode(key, Encoding.UTF8))
.Append("=")
.Append(HttpUtility.UrlEncode(nv[key], Encoding.UTF8));
firstIteration = false;
}
return sb.ToString();
}
}
}
Затем в коде вы можете сделать это:
url.Query = query.ToUtf8UrlEncodedQuery();
Не забудьте добавить директиву using
для namespace
, где вы поместите класс NameValueCollectionExtension
.
Ответ 3
Проблема здесь не в UriBuilder.Query, это UriBuilder.ToString(). Прочтите документацию здесь: https://msdn.microsoft.com/en-us/library/system.uribuilder.tostring(v=vs.110).aspx. Свойство определяется как возвращающее "отображаемую строку" строителя, а не закодированную строку. Uri.ToString() имеет аналогичную проблему, поскольку он не выполняет правильную кодировку.
Используйте вместо этого следующее: url.Uri.AbsoluteUri
, которое всегда будет правильно закодированной строкой. Вам не нужно делать какую-либо кодировку на пути в конструктор (эта часть цели, в конце концов, правильно кодировать вещи).
Ответ 4
Вам нужно использовать:
System.Web.HttpUtility.UrlEncode(key)
Измените код следующим образом:
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
query["model"] = Model;
//code goes here for other parameters....
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
var url = new UriBuilder(apiurl);
url.Query = HttpUtility.UrlEncode(query.ToString());
string xml = client.DownloadString(url.ToString());
XmlDocument doc = new XmlDocument();
//code goes here ....
}
Ответ 5
Если ничего не помогает, просто вручную преобразуйте эти проблематичные символы внутри значений параметров
& to %26
+ to %2B
? to %3F