UriBuilder().查询将错误地编码非ASCII字符

joh*_* Gu 23 .net c# asp.net asp.net-mvc http

我正在开发一个asp.net mvc 4 Web应用程序.我正在使用.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 ....

}
Run Code Online (Sandbox Code Playgroud)

现在我已经注意到一个问题,当这些参数中的一个包含非ASCII承租人如£,¬等....

现在最后的查询将有任何非ASCII字符(例如£)编码错误(as %u00a3).我读到了这个问题,似乎我可以取代: -

url.Query = query.ToString();
Run Code Online (Sandbox Code Playgroud)

url.Query = ri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));    
Run Code Online (Sandbox Code Playgroud)

现在使用后面的方法将编码£%C2%A3正确的编码值.

但我面临的问题是,url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString()));在这种情况下,其中一个参数包含&然后url将具有以下格式, &operation=AddAsset&assetName=&....因此它将假设我传递空assetName参数而不是值= &??

编辑

让我再次总结一下我的问题.我希望能够将我的URL中的以下3个内容传递给第三方API:

  1. 标准字符,如A,B,a,b,1,2,3 ......

  2. 非ASCII字符,例如£,¬.

  3. 并且也是在URL编码用于诸如特殊字符&,+.

现在我尝试了以下两种方法:

方法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 ....

}
Run Code Online (Sandbox Code Playgroud)

在这种方法中,我可以传递值,例如&,+因为它们将被url编码,但如果我想传递非ASCII字符,它们将使用ISO-8859-1进行编码...所以如果我£有价值,我的上面的代码将编码为%u00a3,它将保存在第三方API中,%u00a3而不是£.

方法B:

我用 :

url.Query = Uri.EscapeUriString(HttpUtility.UrlDecode(query.ToString())); 
Run Code Online (Sandbox Code Playgroud)

代替

url.Query = query.ToString();
Run Code Online (Sandbox Code Playgroud)

现在我可以传递非ASCII字符,£因为它们将使用UTF8而不是ISO-8859-1正确编码.但我无法传递值,例如&因为我的网址会被第三方API错误地读取..例如,如果我想传递assetName=&我的网址,请看如下:

&operation=Add&assetName=&
Run Code Online (Sandbox Code Playgroud)

所以第三部分API将假设我传递为空assetName,而我试图将其值传递为&...

所以不知道我怎么能同时通过非ASCII字符+字符,例如&,+????

DWr*_*ght 9

你可以System.Net.Http.FormUrlEncodedContent改用.

这适用于名称/值配对的字典和字典,不像NameValueCollection"不正确"地映射字符,例如£无用的转义(%u00a3在您的情况下).

相反,它FormUrlEncodedContent可以在其构造函数中使用字典.当您从中读取字符串时,它将正确地对字典值进行urlencoded.

它将正确并统一地处理您遇到问题的两种情况:

  • £ (超过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;
Run Code Online (Sandbox Code Playgroud)

queryString将包含item1=%C2%A3&item2=%26&item3=xyz.