Подтвердить что ты не робот

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 + символы, такие как &, +????

4b9b3361

Ответ 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